Крупное обновление LauncherRequest

Есть совместимость с предыдущими версиями
This commit is contained in:
Gravit 2018-10-25 19:36:57 +07:00
parent 23677bd5a3
commit 96bca9aa5d
No known key found for this signature in database
GPG key ID: 061981E1E85D3216
17 changed files with 328 additions and 104 deletions

View file

@ -4,6 +4,7 @@
import java.nio.file.Path;
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launcher.serialize.signed.DigestBytesHolder;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.launcher.serialize.signed.SignedBytesHolder;
import ru.gravit.launchserver.LaunchServer;
@ -15,8 +16,8 @@ public abstract class LauncherBinary {
protected final Path binaryFile;
protected final Path syncBinaryFile;
private volatile SignedBytesHolder binary;
private volatile byte[] hash;
private volatile DigestBytesHolder binary;
private volatile byte[] sign;
protected LauncherBinary(LaunchServer server, Path binaryFile) {
@ -41,19 +42,19 @@ public final boolean exists() {
}
public final SignedBytesHolder getBytes() {
public final DigestBytesHolder getBytes() {
return binary;
}
public final byte[] getHash() {
return hash;
public final byte[] getSign() {
return sign;
}
public final boolean sync() throws IOException {
boolean exists = exists();
binary = exists ? new SignedBytesHolder(IOHelper.read(syncBinaryFile), server.privateKey) : null;
hash = exists ? SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512,IOHelper.newInput(syncBinaryFile)) : null;
binary = exists ? new DigestBytesHolder(IOHelper.read(syncBinaryFile), SecurityHelper.DigestAlgorithm.SHA512) : null;
sign = exists ? SecurityHelper.sign(IOHelper.read(syncBinaryFile),server.privateKey) : null;
return exists;
}
}

View file

@ -4,8 +4,8 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launchserver.response.auth.*;
import ru.gravit.launchserver.response.update.*;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.launcher.request.RequestException;
import ru.gravit.launcher.request.RequestType;
@ -15,10 +15,6 @@
import ru.gravit.launchserver.response.profile.BatchProfileByUsernameResponse;
import ru.gravit.launchserver.response.profile.ProfileByUUIDResponse;
import ru.gravit.launchserver.response.profile.ProfileByUsernameResponse;
import ru.gravit.launchserver.response.update.LauncherResponse;
import ru.gravit.launchserver.response.update.ProfilesResponse;
import ru.gravit.launchserver.response.update.UpdateListResponse;
import ru.gravit.launchserver.response.update.UpdateResponse;
public abstract class Response {
@FunctionalInterface
@ -47,6 +43,7 @@ public static void registerResponses() {
registerResponse(RequestType.PROFILE_BY_USERNAME.getNumber(), ProfileByUsernameResponse::new);
registerResponse(RequestType.PROFILE_BY_UUID.getNumber(), ProfileByUUIDResponse::new);
registerResponse(RequestType.LEGACYLAUNCHER.getNumber(), LegacyLauncherResponse::new);
registerResponse(RequestType.LAUNCHER.getNumber(), LauncherResponse::new);
registerResponse(RequestType.UPDATE_LIST.getNumber(), UpdateListResponse::new);
registerResponse(RequestType.UPDATE.getNumber(), UpdateResponse::new);

View file

@ -1,16 +1,21 @@
package ru.gravit.launchserver.response.update;
import java.io.IOException;
import java.util.Collection;
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.signed.DigestBytesHolder;
import ru.gravit.launcher.serialize.signed.SignedBytesHolder;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.manangers.SessionManager;
import ru.gravit.launchserver.response.Response;
import ru.gravit.launchserver.socket.Client;
import ru.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.security.SignatureException;
import java.util.Arrays;
import java.util.Collection;
public final class LauncherResponse extends Response {
@ -21,25 +26,23 @@ public LauncherResponse(LaunchServer server, long session, HInput input, HOutput
@Override
public void reply() throws IOException {
// Resolve launcher binary
SignedBytesHolder bytes = (input.readBoolean() ? server.launcherEXEBinary : server.launcherBinary).getBytes();
DigestBytesHolder bytes = (input.readBoolean() ? server.launcherEXEBinary : server.launcherBinary).getBytes();
if (bytes == null) {
requestError("Missing launcher binary");
return;
}
writeNoError(output);
// Update launcher binary
output.writeByteArray(bytes.getSign(), -SecurityHelper.RSA_KEY_LENGTH);
output.flush();
if (input.readBoolean()) {
Client client = server.sessionManager.getOrNewClient(session);
byte[] digest = input.readByteArray(0);
if(!Arrays.equals(bytes.getDigest(), digest))
{
writeNoError(output);
output.writeBoolean(true);
output.writeByteArray(bytes.getBytes(), 0);
return; // Launcher will be restarted
client.checkSign = false;
return;
}
// Write clients profiles list
Collection<SignedObjectHolder<ClientProfile>> profiles = server.getProfiles();
output.writeLength(profiles.size(), 0);
for (SignedObjectHolder<ClientProfile> profile : profiles)
profile.write(output);
writeNoError(output);
output.writeBoolean(false);
client.checkSign = true;
}
}

View file

@ -0,0 +1,42 @@
package ru.gravit.launchserver.response.update;
import java.io.IOException;
import java.util.Collection;
import ru.gravit.launcher.serialize.signed.DigestBytesHolder;
import ru.gravit.launchserver.binary.LauncherBinary;
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.signed.SignedBytesHolder;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.launchserver.LaunchServer;
import ru.gravit.launchserver.response.Response;
public final class LegacyLauncherResponse extends Response {
public LegacyLauncherResponse(LaunchServer server, long session, HInput input, HOutput output, String ip) {
super(server, session, input, output, ip);
}
@Override
public void reply() throws IOException {
// Resolve launcher binary
LauncherBinary bytes = (input.readBoolean() ? server.launcherEXEBinary : server.launcherBinary);
if (bytes == null) {
requestError("Missing launcher binary");
return;
}
writeNoError(output);
// Update launcher binary
output.writeByteArray(bytes.getSign(), -SecurityHelper.RSA_KEY_LENGTH);
output.flush();
if (input.readBoolean()) {
output.writeByteArray(bytes.getBytes().getBytes(), 0);
return; // Launcher will be restarted
}
requestError("You must update");
}
}

View file

@ -23,7 +23,7 @@ public void reply() throws IOException {
// Resolve launcher binary
Client client = server.sessionManager.getClient(session);
input.readBoolean();
if(client.type == Client.Type.USER) {
if(client.type == Client.Type.USER && !client.checkSign) {
LogHelper.warning("User session: %d ip %s try get profiles",session,ip);
requestError("Assess denied");
return;

View file

@ -10,6 +10,7 @@ public class Client {
public Type type;
public ClientProfile profile;
public boolean isAuth;
public boolean checkSign;
public ClientPermissions permissions;
public String username;
@ -20,6 +21,7 @@ public Client(long session) {
isAuth = false;
permissions = ClientPermissions.DEFAULT;
username = "";
checkSign = false;
}
//Данные ваторизации
public void up() {

View file

@ -27,7 +27,7 @@ public void execute(WebSocketService service, ChannelHandlerContext ctx, Client
byte[] bytes = Base64.getDecoder().decode(hash);
if(launcher_type == 1) // JAR
{
byte[] hash = LaunchServer.server.launcherBinary.getHash();
byte[] hash = LaunchServer.server.launcherBinary.getBytes().getDigest();
if(hash == null) service.sendObjectAndClose(ctx, new Result(true,JAR_URL));
if(Arrays.equals(bytes, hash))
{
@ -38,7 +38,7 @@ public void execute(WebSocketService service, ChannelHandlerContext ctx, Client
}
} else if(launcher_type == 2) //EXE
{
byte[] hash = LaunchServer.server.launcherEXEBinary.getHash();
byte[] hash = LaunchServer.server.launcherEXEBinary.getBytes().getDigest();
if(hash == null) service.sendObjectAndClose(ctx, new Result(true,EXE_URL));
if(Arrays.equals(bytes, hash))
{

View file

@ -147,20 +147,23 @@ function verifyLauncher(e) {
return;
}
settings.lastSign = result.sign;
settings.lastProfiles = result.profiles;
processing.resetOverlay();
// Init offline if set
if (settings.offline) {
initOffline();
initOffline();
}
// Update profiles list and hide overlay
updateProfilesList(result.profiles);
overlay.hide(0, function() {
if (cliParams.autoLogin) {
goAuth(null);
}
overlay.show(processing.overlay, function(event) makeProfilesRequest(function(result) {
settings.lastProfiles = result.profiles;
// Update profiles list and hide overlay
updateProfilesList(result.profiles);
overlay.hide(0, function() {
if (cliParams.autoLogin) {
goAuth(null);
}
});
});
}));
}

View file

@ -83,6 +83,22 @@ function makeLauncherRequest(callback) {
task.updateMessage("Обновление списка серверов");
startTask(task);
}
function makeProfilesRequest(callback) {
var task = newRequestTask(new ProfilesRequest());
// Set task properties and start
processing.setTaskProperties(task, callback, function() {
if (settings.offline) {
return;
}
// Repeat request, but in offline mode
settings.offline = true;
overlay.swap(2500, processing.overlay, function() makeProfilesRequest(callback));
}, false);
task.updateMessage("Обновление списка серверов");
startTask(task);
}
function makeAuthRequest(login, rsaPassword, callback) {
var task = rsaPassword === null ? newTask(offlineAuthRequest(login)) :

View file

@ -24,6 +24,7 @@ var JoinServerRequest = JoinServerRequestClass.static;
var CheckServerRequest = CheckServerRequestClass.static;
var UpdateRequest = UpdateRequestClass.static;
var LauncherRequest = LauncherRequestClass.static;
var ProfilesRequest = ProfilesRequestClass.static;
var ProfileByUsernameRequest = ProfileByUsernameRequestClass.static;
var ProfileByUUIDRequest = ProfileByUUIDRequestClass.static;
var BatchProfileByUsernameRequest = BatchProfileByUsernameRequestClass.static;

View file

@ -3,8 +3,6 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
@ -23,6 +21,8 @@
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.hasher.HashedEntry;
import ru.gravit.launcher.hasher.HashedFile;
import ru.gravit.launcher.request.update.LauncherRequest;
import ru.gravit.launcher.request.update.ProfilesRequest;
import ru.gravit.utils.HTTPRequest;
import ru.gravit.utils.helper.CommonHelper;
import ru.gravit.utils.helper.EnvHelper;
@ -42,7 +42,7 @@
import ru.gravit.launcher.request.auth.AuthRequest;
import ru.gravit.launcher.request.auth.CheckServerRequest;
import ru.gravit.launcher.request.auth.JoinServerRequest;
import ru.gravit.launcher.request.update.LauncherRequest;
import ru.gravit.launcher.request.update.LegacyLauncherRequest;
import ru.gravit.launcher.request.update.UpdateRequest;
import ru.gravit.launcher.request.uuid.BatchProfileByUsernameRequest;
import ru.gravit.launcher.request.uuid.ProfileByUUIDRequest;
@ -90,6 +90,7 @@ public static void addLauncherClassBindings(Map<String, Object> bindings) {
bindings.put("CheckServerRequestClass", CheckServerRequest.class);
bindings.put("UpdateRequestClass", UpdateRequest.class);
bindings.put("LauncherRequestClass", LauncherRequest.class);
bindings.put("ProfilesRequestClass", ProfilesRequest.class);
bindings.put("ProfileByUsernameRequestClass", ProfileByUsernameRequest.class);
bindings.put("ProfileByUUIDRequestClass", ProfileByUUIDRequest.class);
bindings.put("BatchProfileByUsernameRequestClass", BatchProfileByUsernameRequest.class);

View file

@ -1,6 +1,5 @@
package ru.gravit.launcher.client;
import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.lang.invoke.MethodHandle;
@ -8,7 +7,6 @@
import java.lang.invoke.MethodType;
import java.net.*;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
@ -35,10 +33,9 @@
import ru.gravit.utils.helper.JVMHelper.OS;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.utils.helper.VerifyHelper;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.profiles.PlayerProfile;
import ru.gravit.launcher.request.update.LauncherRequest;
import ru.gravit.launcher.request.update.LegacyLauncherRequest;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
@ -440,7 +437,7 @@ public static void main(String... args) throws Throwable {
Launcher.modulesManager.initModules();
// Verify ClientLauncher sign and classpath
LogHelper.debug("Verifying ClientLauncher sign and classpath");
SecurityHelper.verifySign(LauncherRequest.BINARY_PATH, params.launcherSign, publicKey);
SecurityHelper.verifySign(LegacyLauncherRequest.BINARY_PATH, params.launcherSign, publicKey);
LinkedList<Path> classPath = resolveClassPathList(params.clientDir, profile.object.getClassPath());
for (Path classpathURL : classPath) {
LauncherAgent.addJVMClassPath(classpathURL.toAbsolutePath().toString());
@ -479,7 +476,7 @@ public void launchLocal(SignedObjectHolder<HashedDir> assetHDir, SignedObjectHol
SignedObjectHolder<ClientProfile> profile, Params params) throws Throwable {
RSAPublicKey publicKey = Launcher.getConfig().publicKey;
LogHelper.debug("Verifying ClientLauncher sign and classpath");
SecurityHelper.verifySign(LauncherRequest.BINARY_PATH, params.launcherSign, publicKey);
SecurityHelper.verifySign(LegacyLauncherRequest.BINARY_PATH, params.launcherSign, publicKey);
LinkedList<Path> classPath = resolveClassPathList(params.clientDir, profile.object.getClassPath());
for (Path classpathURL : classPath) {
LauncherAgent.addJVMClassPath(classpathURL.toAbsolutePath().toString());

View file

@ -5,8 +5,7 @@
import ru.gravit.launcher.hasher.FileNameMatcher;
import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.request.Request;
import ru.gravit.launcher.request.RequestException;
import ru.gravit.launcher.request.update.LauncherRequest;
import ru.gravit.launcher.request.update.LegacyLauncherRequest;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.utils.helper.SecurityHelper;
@ -30,17 +29,17 @@ public HashedDirRunnable offlineUpdateRequest(String dirName, Path dir, SignedOb
};
}
@LauncherAPI
public LauncherRequest.Result offlineLauncherRequest() throws IOException, SignatureException {
public LegacyLauncherRequest.Result offlineLauncherRequest() throws IOException, SignatureException {
if (settings.lastSign == null || settings.lastProfiles.isEmpty()) {
Request.requestError("Запуск в оффлайн-режиме невозможен");
}
// Verify launcher signature
SecurityHelper.verifySign(LauncherRequest.BINARY_PATH,
SecurityHelper.verifySign(LegacyLauncherRequest.BINARY_PATH,
settings.lastSign, Launcher.getConfig().publicKey);
// Return last sign and profiles
return new LauncherRequest.Result(null,settings.lastSign,settings.lastProfiles);
return new LegacyLauncherRequest.Result(null,settings.lastSign,settings.lastProfiles);
}
@FunctionalInterface
public interface HashedDirRunnable {

View file

@ -1,39 +1,34 @@
package ru.gravit.launcher.request.update;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launcher.LauncherConfig;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.request.Request;
import ru.gravit.launcher.request.RequestType;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.JVMHelper;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.nio.file.Path;
import java.security.SignatureException;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launcher.LauncherConfig;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.JVMHelper;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.request.Request;
import ru.gravit.launcher.request.RequestType;
import ru.gravit.launcher.request.update.LauncherRequest.Result;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
public final class LauncherRequest extends Request<Result> {
public final class LauncherRequest extends Request<LauncherRequest.Result> {
public static final class Result {
@LauncherAPI
public final List<SignedObjectHolder<ClientProfile>> profiles;
private final byte[] binary;
private final byte[] sign;
private final byte[] digest;
public Result(byte[] binary, byte[] sign, List<SignedObjectHolder<ClientProfile>> profiles) {
public Result(byte[] binary, byte[] sign) {
this.binary = binary == null ? null : binary.clone();
this.sign = sign.clone();
this.profiles = Collections.unmodifiableList(profiles);
this.digest = sign.clone();
}
@LauncherAPI
@ -42,8 +37,8 @@ public byte[] getBinary() {
}
@LauncherAPI
public byte[] getSign() {
return sign.clone();
public byte[] getDigest() {
return digest.clone();
}
}
@ -55,9 +50,6 @@ public byte[] getSign() {
@LauncherAPI
public static void update(LauncherConfig config, Result result) throws SignatureException, IOException {
SecurityHelper.verifySign(result.binary, result.sign, config.publicKey);
// Prepare process builder to start new instance (java -jar works for Launch4J's EXE too)
List<String> args = new ArrayList<>(8);
args.add(IOHelper.resolveJavaBin(null).toString());
if (LogHelper.isDebugEnabled())
@ -96,31 +88,23 @@ public Integer getType() {
@Override
@SuppressWarnings("CallToSystemExit")
protected Result requestDo(HInput input, HOutput output) throws Exception {
RSAPublicKey publicKey = config.publicKey;
Path launcherPath = IOHelper.getCodeSource(LauncherRequest.class);
byte[] digest = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512,launcherPath);
byte[] sign;
output.writeBoolean(EXE_BINARY);
output.writeByteArray(digest,0);
output.flush();
readError(input);
// Verify launcher sign
RSAPublicKey publicKey = config.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();
boolean shouldUpdate = input.readBoolean();
if (shouldUpdate) {
byte[] binary = input.readByteArray(0);
SecurityHelper.verifySign(binary, sign, config.publicKey);
return new Result(binary, sign, Collections.emptyList());
return new Result(binary, digest);
}
// 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(null, sign, profiles);
return new Result(null, digest);
}
}

View file

@ -0,0 +1,126 @@
package ru.gravit.launcher.request.update;
import java.io.IOException;
import java.nio.file.Path;
import java.security.SignatureException;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launcher.LauncherConfig;
import ru.gravit.utils.helper.IOHelper;
import ru.gravit.utils.helper.JVMHelper;
import ru.gravit.utils.helper.LogHelper;
import ru.gravit.utils.helper.SecurityHelper;
import ru.gravit.launcher.profiles.ClientProfile;
import ru.gravit.launcher.request.Request;
import ru.gravit.launcher.request.RequestType;
import ru.gravit.launcher.request.update.LegacyLauncherRequest.Result;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
public final class LegacyLauncherRequest extends Request<Result> {
public static final class Result {
@LauncherAPI
public final List<SignedObjectHolder<ClientProfile>> profiles;
private final byte[] binary;
private final byte[] sign;
public Result(byte[] binary, byte[] sign, List<SignedObjectHolder<ClientProfile>> profiles) {
this.binary = binary == null ? null : binary.clone();
this.sign = sign.clone();
this.profiles = Collections.unmodifiableList(profiles);
}
@LauncherAPI
public byte[] getBinary() {
return binary == null ? null : binary.clone();
}
@LauncherAPI
public byte[] getSign() {
return sign.clone();
}
}
@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 static void update(LauncherConfig config, Result result) throws SignatureException, IOException {
SecurityHelper.verifySign(result.binary, result.sign, config.publicKey);
// Prepare process builder to start new instance (java -jar works for Launch4J's EXE too)
List<String> args = new ArrayList<>(8);
args.add(IOHelper.resolveJavaBin(null).toString());
if (LogHelper.isDebugEnabled())
args.add(JVMHelper.jvmProperty(LogHelper.DEBUG_PROPERTY, Boolean.toString(LogHelper.isDebugEnabled())));
if (LauncherConfig.ADDRESS_OVERRIDE != null)
args.add(JVMHelper.jvmProperty(LauncherConfig.ADDRESS_OVERRIDE_PROPERTY, LauncherConfig.ADDRESS_OVERRIDE));
args.add("-jar");
args.add(BINARY_PATH.toString());
ProcessBuilder builder = new ProcessBuilder(args.toArray(new String[0]));
builder.inheritIO();
// Rewrite and start new instance
IOHelper.write(BINARY_PATH, result.binary);
builder.start();
// Kill current instance
JVMHelper.RUNTIME.exit(255);
throw new AssertionError("Why Launcher wasn't restarted?!");
}
@LauncherAPI
public LegacyLauncherRequest() {
this(null);
}
@LauncherAPI
public LegacyLauncherRequest(LauncherConfig config) {
super(config);
}
@Override
public Integer getType() {
return RequestType.LEGACYLAUNCHER.getNumber();
}
@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 = config.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, config.publicKey);
return new Result(binary, sign, Collections.emptyList());
}
// 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(null, sign, profiles);
}
}

View file

@ -8,10 +8,10 @@
public enum RequestType implements EnumSerializer.Itf {
PING(0), // Ping request
LAUNCHER(1), UPDATE(2), UPDATE_LIST(3), // Update requests
LEGACYLAUNCHER(1), UPDATE(2), UPDATE_LIST(3), // Update requests
AUTH(4), JOIN_SERVER(5), CHECK_SERVER(6), // Auth requests
PROFILE_BY_USERNAME(7), PROFILE_BY_UUID(8), BATCH_PROFILE_BY_USERNAME(9), // Profile requests
PROFILES(10),SERVERAUTH(11), SETPROFILE(12),
PROFILES(10),SERVERAUTH(11), SETPROFILE(12),LAUNCHER(13),
CUSTOM(255); // Custom requests
private static final EnumSerializer<RequestType> SERIALIZER = new EnumSerializer<>(RequestType.class);

View file

@ -0,0 +1,52 @@
package ru.gravit.launcher.serialize.signed;
import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launcher.serialize.HInput;
import ru.gravit.launcher.serialize.HOutput;
import ru.gravit.launcher.serialize.stream.StreamObject;
import ru.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;
public class DigestBytesHolder extends StreamObject {
protected final byte[] bytes;
private final byte[] digest;
@LauncherAPI
public DigestBytesHolder(byte[] bytes, byte[] digest, SecurityHelper.DigestAlgorithm algorithm) throws SignatureException {
if(Arrays.equals(SecurityHelper.digest(algorithm,bytes),digest)) throw new SignatureException("Invalid digest");
this.bytes = bytes.clone();
this.digest = digest.clone();
}
@LauncherAPI
public DigestBytesHolder(byte[] bytes, SecurityHelper.DigestAlgorithm algorithm) {
this.bytes = bytes.clone();
this.digest = SecurityHelper.digest(algorithm,bytes);
}
@LauncherAPI
public DigestBytesHolder(HInput input, SecurityHelper.DigestAlgorithm algorithm) throws IOException, SignatureException {
this(input.readByteArray(0), input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH),algorithm);
}
@LauncherAPI
public final byte[] getBytes() {
return bytes.clone();
}
@LauncherAPI
public final byte[] getDigest() {
return digest.clone();
}
@Override
public final void write(HOutput output) throws IOException {
output.writeByteArray(bytes, 0);
output.writeByteArray(digest, -SecurityHelper.RSA_KEY_LENGTH);
}
}