[FEATURE] Use buildSecrets in UpdatesProvider

This commit is contained in:
Gravita 2025-06-18 00:08:22 +07:00
parent 2d046f7d7b
commit a959414c64
4 changed files with 70 additions and 16 deletions

View file

@ -2,6 +2,8 @@
import org.apache.logging.log4j.LogManager;
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.utils.helper.IOHelper;
import pro.gravit.utils.helper.SecurityHelper;
@ -9,23 +11,33 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
public class LocalUpdatesProvider extends UpdatesProvider {
private transient final Logger logger = LogManager.getLogger();
public String updatesDir = "updates";
public String binaryName = "Launcher";
public String buildSecretsFile = "build-secrets.json";
public Map<UpdateVariant, String> urls = new HashMap<>(Map.of(
UpdateVariant.JAR, "http://localhost:9274/Launcher.jar",
UpdateVariant.EXE, "http://localhost:9274/Launcher.exe"
));
public transient JsonConfigurable<BuildSecretsInfo> buildSecretsJson;
private final transient Map<UpdateVariant, byte[]> hashMap = new HashMap<>();
@Override
public void init(LaunchServer 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 {
sync(UpdateVariant.JAR);
sync(UpdateVariant.EXE);
@ -35,11 +47,13 @@ public void init(LaunchServer server) {
}
@Override
public void pushUpdate(Map<UpdateVariant, Path> files) throws IOException {
for(var e : files.entrySet()) {
IOHelper.copy(e.getValue(), getUpdate(e.getKey()));
sync(e.getKey());
public void pushUpdate(List<UpdateUploadInfo> files) throws IOException {
for(var e : files) {
IOHelper.copy(e.path(), getUpdate(e.variant()));
buildSecretsJson.getConfig().secrets().put(e.variant(), e.secrets());
sync(e.variant());
}
buildSecretsJson.saveConfig();
}
public void sync(UpdateVariant variant) throws IOException {
@ -69,14 +83,32 @@ public Path getUpdate(UpdateVariant variant) {
}
@Override
public UpdateInfo checkUpdates(UpdateVariant variant, byte[] digest) {
public UpdateInfo checkUpdates(UpdateVariant variant, BuildSecretsCheck buildSecretsCheck) {
byte[] hash = hashMap.get(variant);
if (hash == null) {
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 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;
}
}
}

View file

@ -2,10 +2,14 @@
import pro.gravit.launchserver.LaunchServer;
import pro.gravit.utils.ProviderMap;
import pro.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;
public abstract class UpdatesProvider {
@ -25,8 +29,16 @@ public void init(LaunchServer server) {
this.server = server;
}
public abstract void pushUpdate(Map<UpdateVariant, Path> files) throws IOException;
public abstract UpdateInfo checkUpdates(UpdateVariant variant, byte[] digest);
public abstract void pushUpdate(List<UpdateUploadInfo> files) throws IOException;
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() {
}
@ -38,4 +50,16 @@ public enum UpdateVariant {
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) {
}
}

View file

@ -39,7 +39,8 @@ public void build() throws IOException {
}
long time_end = System.currentTimeMillis();
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 {
logger.warn("Missing {} binary file", getVariant());
}

View file

@ -49,10 +49,7 @@ public void execute(ChannelHandlerContext ctx, Client client) {
variant = UpdatesProvider.UpdateVariant.EXE;
}
byte[] hashToCheck = bytes;
if(!checkSecure(secureHash, secureSalt)) {
hashToCheck = null; // Always need update
}
UpdatesProvider.UpdateInfo info = server.config.updatesProvider.checkUpdates(variant, hashToCheck);
UpdatesProvider.UpdateInfo info = server.config.updatesProvider.checkUpdates(variant, new UpdatesProvider.BuildSecretsCheck(secureHash, secureSalt, hashToCheck));
if (info != null) {
sendResult(new LauncherRequestEvent(true, info.url()));
} else {