mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-06-28 20:18:10 +03:00
[FEATURE] Use buildSecrets in UpdatesProvider
This commit is contained in:
parent
2d046f7d7b
commit
a959414c64
4 changed files with 70 additions and 16 deletions
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import pro.gravit.launcher.base.config.JsonConfigurable;
|
||||||
|
import pro.gravit.launcher.base.config.SimpleConfigurable;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
@ -9,23 +11,33 @@
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class LocalUpdatesProvider extends UpdatesProvider {
|
public class LocalUpdatesProvider extends UpdatesProvider {
|
||||||
private transient final Logger logger = LogManager.getLogger();
|
private transient final Logger logger = LogManager.getLogger();
|
||||||
public String updatesDir = "updates";
|
public String updatesDir = "updates";
|
||||||
public String binaryName = "Launcher";
|
public String binaryName = "Launcher";
|
||||||
|
public String buildSecretsFile = "build-secrets.json";
|
||||||
public Map<UpdateVariant, String> urls = new HashMap<>(Map.of(
|
public Map<UpdateVariant, String> urls = new HashMap<>(Map.of(
|
||||||
UpdateVariant.JAR, "http://localhost:9274/Launcher.jar",
|
UpdateVariant.JAR, "http://localhost:9274/Launcher.jar",
|
||||||
UpdateVariant.EXE, "http://localhost:9274/Launcher.exe"
|
UpdateVariant.EXE, "http://localhost:9274/Launcher.exe"
|
||||||
));
|
));
|
||||||
|
public transient JsonConfigurable<BuildSecretsInfo> buildSecretsJson;
|
||||||
private final transient Map<UpdateVariant, byte[]> hashMap = new HashMap<>();
|
private final transient Map<UpdateVariant, byte[]> hashMap = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(LaunchServer server) {
|
public void init(LaunchServer server) {
|
||||||
super.init(server);
|
super.init(server);
|
||||||
|
buildSecretsJson = new SimpleConfigurable<>(BuildSecretsInfo.class, Path.of(buildSecretsFile));
|
||||||
|
if(server.env == LaunchServer.LaunchServerEnv.TEST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
buildSecretsJson.generateConfigIfNotExists();
|
||||||
|
buildSecretsJson.loadConfig();
|
||||||
|
} catch (Exception e) {
|
||||||
|
buildSecretsJson.setConfig(buildSecretsJson.getDefaultConfig());
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
sync(UpdateVariant.JAR);
|
sync(UpdateVariant.JAR);
|
||||||
sync(UpdateVariant.EXE);
|
sync(UpdateVariant.EXE);
|
||||||
|
@ -35,11 +47,13 @@ public void init(LaunchServer server) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pushUpdate(Map<UpdateVariant, Path> files) throws IOException {
|
public void pushUpdate(List<UpdateUploadInfo> files) throws IOException {
|
||||||
for(var e : files.entrySet()) {
|
for(var e : files) {
|
||||||
IOHelper.copy(e.getValue(), getUpdate(e.getKey()));
|
IOHelper.copy(e.path(), getUpdate(e.variant()));
|
||||||
sync(e.getKey());
|
buildSecretsJson.getConfig().secrets().put(e.variant(), e.secrets());
|
||||||
|
sync(e.variant());
|
||||||
}
|
}
|
||||||
|
buildSecretsJson.saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sync(UpdateVariant variant) throws IOException {
|
public void sync(UpdateVariant variant) throws IOException {
|
||||||
|
@ -69,14 +83,32 @@ public Path getUpdate(UpdateVariant variant) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UpdateInfo checkUpdates(UpdateVariant variant, byte[] digest) {
|
public UpdateInfo checkUpdates(UpdateVariant variant, BuildSecretsCheck buildSecretsCheck) {
|
||||||
byte[] hash = hashMap.get(variant);
|
byte[] hash = hashMap.get(variant);
|
||||||
if (hash == null) {
|
if (hash == null) {
|
||||||
return null; // We dont have this file
|
return null; // We dont have this file
|
||||||
}
|
}
|
||||||
if(Arrays.equals(digest, hash)) {
|
if(checkSecureHash(buildSecretsCheck.secureHash(), buildSecretsCheck.secureSalt(), buildSecretsJson.getConfig().secrets().get(variant).secureToken()) && Arrays.equals(buildSecretsCheck.digest(), hash)) {
|
||||||
return null; // Launcher already updated
|
return null; // Launcher already updated
|
||||||
}
|
}
|
||||||
return new UpdateInfo(urls.get(variant));
|
return new UpdateInfo(urls.get(variant));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class BuildSecretsInfo {
|
||||||
|
private Map<UpdateVariant, BuildSecrets> secrets = new HashMap<>();
|
||||||
|
|
||||||
|
public BuildSecretsInfo(Map<UpdateVariant, BuildSecrets> secrets) {
|
||||||
|
this.secrets = secrets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuildSecretsInfo() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<UpdateVariant, BuildSecrets> secrets() {
|
||||||
|
return secrets;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,14 @@
|
||||||
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.utils.ProviderMap;
|
import pro.gravit.utils.ProviderMap;
|
||||||
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public abstract class UpdatesProvider {
|
public abstract class UpdatesProvider {
|
||||||
|
@ -25,8 +29,16 @@ public void init(LaunchServer server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void pushUpdate(Map<UpdateVariant, Path> files) throws IOException;
|
public abstract void pushUpdate(List<UpdateUploadInfo> files) throws IOException;
|
||||||
public abstract UpdateInfo checkUpdates(UpdateVariant variant, byte[] digest);
|
public abstract UpdateInfo checkUpdates(UpdateVariant variant, BuildSecretsCheck buildSecretsCheck);
|
||||||
|
|
||||||
|
protected boolean checkSecureHash(String secureHash, String secureSalt, String privateSecureToken) {
|
||||||
|
if (secureHash == null || secureSalt == null) return false;
|
||||||
|
byte[] normal_hash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256,
|
||||||
|
privateSecureToken.concat(".").concat(secureSalt));
|
||||||
|
byte[] launcher_hash = Base64.getDecoder().decode(secureHash);
|
||||||
|
return Arrays.equals(normal_hash, launcher_hash);
|
||||||
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
}
|
}
|
||||||
|
@ -38,4 +50,16 @@ public enum UpdateVariant {
|
||||||
public record UpdateInfo(String url) {
|
public record UpdateInfo(String url) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record UpdateUploadInfo(Path path, UpdateVariant variant, BuildSecrets secrets) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public record BuildSecrets(String secureToken, byte[] digest) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public record BuildSecretsCheck(String secureHash, String secureSalt, byte[] digest) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,8 @@ public void build() throws IOException {
|
||||||
}
|
}
|
||||||
long time_end = System.currentTimeMillis();
|
long time_end = System.currentTimeMillis();
|
||||||
if(thisPath != null) {
|
if(thisPath != null) {
|
||||||
server.config.updatesProvider.pushUpdate(Map.of(getVariant(), thisPath));
|
// TODO fix me
|
||||||
|
server.config.updatesProvider.pushUpdate(List.of(new UpdatesProvider.UpdateUploadInfo(thisPath, getVariant(), new UpdatesProvider.BuildSecrets(server.runtime.clientCheckSecret, null))));
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Missing {} binary file", getVariant());
|
logger.warn("Missing {} binary file", getVariant());
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,10 +49,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
|
||||||
variant = UpdatesProvider.UpdateVariant.EXE;
|
variant = UpdatesProvider.UpdateVariant.EXE;
|
||||||
}
|
}
|
||||||
byte[] hashToCheck = bytes;
|
byte[] hashToCheck = bytes;
|
||||||
if(!checkSecure(secureHash, secureSalt)) {
|
UpdatesProvider.UpdateInfo info = server.config.updatesProvider.checkUpdates(variant, new UpdatesProvider.BuildSecretsCheck(secureHash, secureSalt, hashToCheck));
|
||||||
hashToCheck = null; // Always need update
|
|
||||||
}
|
|
||||||
UpdatesProvider.UpdateInfo info = server.config.updatesProvider.checkUpdates(variant, hashToCheck);
|
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
sendResult(new LauncherRequestEvent(true, info.url()));
|
sendResult(new LauncherRequestEvent(true, info.url()));
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue