package launcher.request.update;
import java.nio.file.Path;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import launcher.Launcher;
import launcher.LauncherAPI;
import launcher.client.ClientProfile;
import launcher.helper.IOHelper;
import launcher.helper.JVMHelper;
import launcher.helper.SecurityHelper;
import launcher.request.Request;
import launcher.serialize.HInput;
import launcher.serialize.HOutput;
import launcher.serialize.signed.SignedObjectHolder;
public final class LauncherRequest extends Request<LauncherRequest.Result> {
@LauncherAPI public static final Path BINARY_PATH = IOHelper.getCodeSource(Launcher.class);
@LauncherAPI public static final boolean EXE_BINARY = IOHelper.hasExtension(BINARY_PATH, "exe");
@LauncherAPI
public LauncherRequest() {
}
@Override
public Type getType() {
return Type.LAUNCHER;
}
@Override
@SuppressWarnings("CallToSystemExit")
protected Result requestDo(HInput input, HOutput output) throws Exception {
output.writeBoolean(EXE_BINARY);
output.flush();
readError(input);
// Verify launcher sign
RSAPublicKey publicKey = Launcher.getConfig().publicKey;
byte[] sign = input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH);
boolean shouldUpdate = !SecurityHelper.isValidSign(BINARY_PATH, sign, publicKey);
// Update launcher if need
output.writeBoolean(shouldUpdate);
output.flush();
if (shouldUpdate) {
byte[] binary = input.readByteArray(0);
SecurityHelper.verifySign(binary, sign, publicKey);
IOHelper.write(BINARY_PATH, binary);
// Start new launcher instance
ProcessBuilder builder = new ProcessBuilder(IOHelper.resolveJavaBin(null).toString(), "-jar", BINARY_PATH.toString());
builder.inheritIO();
builder.start();
// Exit current instance
JVMHelper.RUNTIME.exit(255);
throw new AssertionError("Why Launcher wasn't restarted?!");
}
// Read clients profiles list
int count = input.readLength(0);
List<SignedObjectHolder<ClientProfile>> profiles = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
profiles.add(new SignedObjectHolder<>(input, publicKey, ClientProfile.RO_ADAPTER));
}
// Return request result
return new Result(sign, profiles);
}
public static final class Result {
@LauncherAPI public final List<SignedObjectHolder<ClientProfile>> profiles;
private final byte[] sign;
private Result(byte[] sign, List<SignedObjectHolder<ClientProfile>> profiles) {
this.sign = Arrays.copyOf(sign, sign.length);
this.profiles = Collections.unmodifiableList(profiles);
}
@LauncherAPI
public byte[] getSign() {
return Arrays.copyOf(sign, sign.length);
}
}
}