mirror of
https://github.com/packwiz/packwiz-installer.git
synced 2025-04-19 21:16:30 +02:00
Redo hashing sytem, pack file reading, write json
This commit is contained in:
parent
8be5cb8e60
commit
fbd54b4604
@ -2,19 +2,21 @@ package link.infra.packwiz.installer;
|
|||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.Writer;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.JsonIOException;
|
import com.google.gson.JsonIOException;
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.moandjiezana.toml.Toml;
|
||||||
|
|
||||||
import link.infra.packwiz.installer.metadata.HashInputStream;
|
|
||||||
import link.infra.packwiz.installer.metadata.HashTypeAdapter;
|
|
||||||
import link.infra.packwiz.installer.metadata.ManifestFile;
|
import link.infra.packwiz.installer.metadata.ManifestFile;
|
||||||
|
import link.infra.packwiz.installer.metadata.PackFile;
|
||||||
|
import link.infra.packwiz.installer.metadata.hash.Hash;
|
||||||
import link.infra.packwiz.installer.request.HandlerManager;
|
import link.infra.packwiz.installer.request.HandlerManager;
|
||||||
import link.infra.packwiz.installer.ui.IUserInterface;
|
import link.infra.packwiz.installer.ui.IUserInterface;
|
||||||
import link.infra.packwiz.installer.ui.InstallProgress;
|
import link.infra.packwiz.installer.ui.InstallProgress;
|
||||||
@ -87,7 +89,7 @@ public class UpdateManager {
|
|||||||
this.checkOptions();
|
this.checkOptions();
|
||||||
|
|
||||||
ui.submitProgress(new InstallProgress("Loading manifest file..."));
|
ui.submitProgress(new InstallProgress("Loading manifest file..."));
|
||||||
Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(byte[].class, new HashTypeAdapter()).create();
|
Gson gson = new Gson();
|
||||||
ManifestFile manifest;
|
ManifestFile manifest;
|
||||||
try {
|
try {
|
||||||
manifest = gson.fromJson(new FileReader(Paths.get(opts.packFolder, opts.manifestFile).toString()),
|
manifest = gson.fromJson(new FileReader(Paths.get(opts.packFolder, opts.manifestFile).toString()),
|
||||||
@ -100,31 +102,47 @@ public class UpdateManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui.submitProgress(new InstallProgress("Loading pack file..."));
|
ui.submitProgress(new InstallProgress("Loading pack file..."));
|
||||||
HashInputStream packFileStream;
|
Hash.HashInputStream packFileStream;
|
||||||
try {
|
try {
|
||||||
InputStream stream = HandlerManager.getFileInputStream(opts.downloadURI);
|
InputStream stream = HandlerManager.getFileInputStream(opts.downloadURI);
|
||||||
if (stream == null) {
|
if (stream == null) {
|
||||||
throw new Exception("Pack file URI is invalid, is it supported?");
|
throw new Exception("Pack file URI is invalid, is it supported?");
|
||||||
}
|
}
|
||||||
packFileStream = new HashInputStream(stream);
|
packFileStream = new Hash.HashInputStream(stream, "sha256");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
// TODO: still launch the game if updating doesn't work?
|
||||||
ui.handleExceptionAndExit(e);
|
ui.handleExceptionAndExit(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: read file
|
PackFile pf;
|
||||||
try {
|
try {
|
||||||
packFileStream.close();
|
pf = new Toml().read(packFileStream).to(PackFile.class);
|
||||||
} catch (IOException e) {
|
} catch (IllegalStateException e) {
|
||||||
// TODO Auto-generated catch block
|
ui.handleExceptionAndExit(e);
|
||||||
e.printStackTrace();
|
return;
|
||||||
}
|
}
|
||||||
byte[] packFileHash = packFileStream.getHashValue();
|
|
||||||
|
Hash packFileHash = packFileStream.get();
|
||||||
if (packFileHash.equals(manifest.packFileHash)) {
|
if (packFileHash.equals(manifest.packFileHash)) {
|
||||||
|
System.out.println("Hash already up to date!");
|
||||||
// WOOO it's already up to date
|
// WOOO it's already up to date
|
||||||
// todo: --force?
|
// todo: --force?
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: save manifest file
|
System.out.println(pf.name);
|
||||||
|
|
||||||
|
|
||||||
|
// When successfully updated
|
||||||
|
manifest.packFileHash = packFileHash;
|
||||||
|
// update other hashes
|
||||||
|
// TODO: don't do this on failure?
|
||||||
|
try (Writer writer = new FileWriter(Paths.get(opts.packFolder, opts.manifestFile).toString())) {
|
||||||
|
gson.toJson(manifest, writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO: add message?
|
||||||
|
ui.handleException(e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkOptions() {
|
protected void checkOptions() {
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
package link.infra.packwiz.installer.metadata;
|
|
||||||
|
|
||||||
import java.io.FilterInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
public class HashInputStream extends FilterInputStream {
|
|
||||||
|
|
||||||
private MessageDigest md;
|
|
||||||
private byte[] output;
|
|
||||||
|
|
||||||
public HashInputStream(InputStream in) throws NoSuchAlgorithmException {
|
|
||||||
super(in);
|
|
||||||
md = MessageDigest.getInstance("SHA-256");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read() throws IOException {
|
|
||||||
int value = super.read();
|
|
||||||
if (value == -1) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
md.update((byte) value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] b, int off, int len) throws IOException {
|
|
||||||
int bytesRead = super.read(b, off, len);
|
|
||||||
if (bytesRead > 0) {
|
|
||||||
md.update(b, off, len);
|
|
||||||
}
|
|
||||||
return bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() throws IOException {
|
|
||||||
throw new IOException("HashInputStream doesn't support reset()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean markSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mark(int readlimit) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getHashValue() {
|
|
||||||
if (output == null) {
|
|
||||||
output = md.digest();
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,5 @@
|
|||||||
|
package link.infra.packwiz.installer.metadata;
|
||||||
|
|
||||||
|
public class IndexFile {
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,13 @@
|
|||||||
package link.infra.packwiz.installer.metadata;
|
package link.infra.packwiz.installer.metadata;
|
||||||
|
|
||||||
|
import link.infra.packwiz.installer.metadata.hash.Hash;
|
||||||
|
|
||||||
public class ManifestFile {
|
public class ManifestFile {
|
||||||
public byte[] packFileHash = null;
|
|
||||||
|
public Hash packFileHash = null;
|
||||||
|
public Hash indexFileHash = null;
|
||||||
|
|
||||||
|
public static class File {
|
||||||
|
public Hash hash = null;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,21 @@
|
|||||||
package link.infra.packwiz.installer.metadata;
|
package link.infra.packwiz.installer.metadata;
|
||||||
|
|
||||||
public class PackFile {
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class PackFile {
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
public IndexFileLoc index;
|
||||||
|
public static class IndexFileLoc {
|
||||||
|
public String file;
|
||||||
|
@SerializedName("hash-format")
|
||||||
|
public String hashFormat;
|
||||||
|
public String hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> versions;
|
||||||
|
public Map<String, Object> client;
|
||||||
|
public Map<String, Object> server;
|
||||||
}
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
package link.infra.packwiz.installer.metadata.hash;
|
||||||
|
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Hash {
|
||||||
|
public final String value;
|
||||||
|
public final String type;
|
||||||
|
|
||||||
|
public Hash(String value, String type) {
|
||||||
|
this.value = value;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Map<String, IHasher> hashTypeConversion = new HashMap<String, IHasher>();
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
hashTypeConversion.put("sha256", new HasherMessageDigest("SHA-256"));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IHasher getHasher() {
|
||||||
|
return hashTypeConversion.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHasher getHasher(String type) {
|
||||||
|
return hashTypeConversion.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null || !(obj instanceof Hash)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Hash hash = (Hash)obj;
|
||||||
|
return type.equals(hash.type) && getHasher().equalValues(value, hash.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HashInputStream extends FilterInputStream {
|
||||||
|
|
||||||
|
private IHasher md;
|
||||||
|
private Hash output;
|
||||||
|
private final String hashType;
|
||||||
|
private Hash compare = null;
|
||||||
|
|
||||||
|
public HashInputStream(InputStream in, String hashType) throws NoSuchAlgorithmException {
|
||||||
|
super(in);
|
||||||
|
this.hashType = hashType;
|
||||||
|
md = hashTypeConversion.get(hashType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashInputStream(InputStream in, Hash compare) throws NoSuchAlgorithmException {
|
||||||
|
this(in, compare.type);
|
||||||
|
this.compare = compare;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
int value = super.read();
|
||||||
|
if (value == -1) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
md.update((byte) value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
int bytesRead = super.read(b, off, len);
|
||||||
|
if (bytesRead > 0) {
|
||||||
|
md.update(b, off, len);
|
||||||
|
}
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() throws IOException {
|
||||||
|
throw new IOException("HashInputStream doesn't support reset()");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean markSupported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mark(int readlimit) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public Hash get() {
|
||||||
|
if (output == null) {
|
||||||
|
String value = md.get();
|
||||||
|
if (value != null) {
|
||||||
|
output = new Hash(value, hashType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNew() {
|
||||||
|
if (output != null) {
|
||||||
|
return !output.equals(compare);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +1,7 @@
|
|||||||
package link.infra.packwiz.installer.metadata;
|
package link.infra.packwiz.installer.metadata.hash;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
public class HashUtils {
|
||||||
|
private HashUtils() {}
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonDeserializer;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
import com.google.gson.JsonSerializationContext;
|
|
||||||
import com.google.gson.JsonSerializer;
|
|
||||||
|
|
||||||
public class HashTypeAdapter implements JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(printHexBinary(src));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return parseHexBinary(json.getAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Why did Java remove this in 1.9????!
|
// Why did Java remove this in 1.9????!
|
||||||
public static byte[] parseHexBinary(String s) {
|
public static byte[] parseHexBinary(String s) {
|
||||||
@ -52,7 +32,7 @@ public class HashTypeAdapter implements JsonSerializer<byte[]>, JsonDeserializer
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final char[] hexCode = "0123456789ABCDEF".toCharArray();
|
private static final char[] hexCode = "0123456789abcdef".toCharArray();
|
||||||
|
|
||||||
public static String printHexBinary(byte[] data) {
|
public static String printHexBinary(byte[] data) {
|
||||||
StringBuilder r = new StringBuilder(data.length*2);
|
StringBuilder r = new StringBuilder(data.length*2);
|
@ -0,0 +1,45 @@
|
|||||||
|
package link.infra.packwiz.installer.metadata.hash;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
public class HasherMessageDigest implements IHasher {
|
||||||
|
MessageDigest md;
|
||||||
|
|
||||||
|
public HasherMessageDigest(String hashType) throws NoSuchAlgorithmException {
|
||||||
|
md = MessageDigest.getInstance(hashType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte[] data) {
|
||||||
|
md.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte[] data, int offset, int length) {
|
||||||
|
md.update(data, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte data) {
|
||||||
|
md.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get() {
|
||||||
|
return HashUtils.printHexBinary(md.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce case insensitivity
|
||||||
|
@Override
|
||||||
|
public boolean equalValues(String a, String b) {
|
||||||
|
if (a == null) {
|
||||||
|
if (b == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return a.equalsIgnoreCase(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package link.infra.packwiz.installer.metadata.hash;
|
||||||
|
|
||||||
|
public interface IHasher {
|
||||||
|
public void update(byte[] data);
|
||||||
|
public void update(byte[] data, int offset, int length);
|
||||||
|
public void update(byte data);
|
||||||
|
public String get();
|
||||||
|
public default boolean equalValues(String a, String b) {
|
||||||
|
if (a == null) {
|
||||||
|
if (b == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return a.equals(b);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user