diff --git a/Launcher/src/main/java/pro/gravit/launcher/runtime/LauncherEngine.java b/Launcher/src/main/java/pro/gravit/launcher/runtime/LauncherEngine.java index b74b4ca0..0a3d7d3e 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/runtime/LauncherEngine.java +++ b/Launcher/src/main/java/pro/gravit/launcher/runtime/LauncherEngine.java @@ -6,19 +6,14 @@ import pro.gravit.launcher.client.*; import pro.gravit.launcher.core.api.LauncherAPI; import pro.gravit.launcher.core.api.LauncherAPIHolder; -import pro.gravit.launcher.core.api.features.AuthFeatureAPI; -import pro.gravit.launcher.core.api.features.ProfileFeatureAPI; -import pro.gravit.launcher.core.api.features.TextureUploadFeatureAPI; -import pro.gravit.launcher.core.api.features.UserFeatureAPI; +import pro.gravit.launcher.core.api.features.*; import pro.gravit.launcher.core.backend.LauncherBackendAPIHolder; import pro.gravit.launcher.runtime.backend.LauncherBackendImpl; import pro.gravit.launcher.runtime.client.*; import pro.gravit.launcher.runtime.client.events.ClientEngineInitPhase; import pro.gravit.launcher.client.events.ClientExitPhase; import pro.gravit.launcher.runtime.client.events.ClientPreGuiPhase; -import pro.gravit.launcher.runtime.console.GetPublicKeyCommand; import pro.gravit.launcher.runtime.console.ModulesCommand; -import pro.gravit.launcher.runtime.console.SignDataCommand; import pro.gravit.launcher.runtime.gui.NoRuntimeProvider; import pro.gravit.launcher.runtime.gui.RuntimeProvider; import pro.gravit.launcher.runtime.managers.ConsoleManager; @@ -34,15 +29,8 @@ import pro.gravit.launcher.start.RuntimeModuleManager; import pro.gravit.utils.helper.*; -import java.io.IOException; -import java.nio.file.Path; import java.nio.file.Paths; -import java.security.KeyPair; -import java.security.SecureRandom; import java.security.cert.X509Certificate; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.InvalidKeySpecException; import java.util.Arrays; import java.util.Map; import java.util.Objects; @@ -55,8 +43,6 @@ public class LauncherEngine { // Instance private final AtomicBoolean started = new AtomicBoolean(false); public RuntimeProvider runtimeProvider; - public ECPublicKey publicKey; - public ECPrivateKey privateKey; public Class basicRuntimeProvider; private LauncherEngine(boolean clientInstance, Class basicRuntimeProvider) { @@ -183,36 +169,6 @@ public static LauncherEngine newInstance(boolean clientInstance, Class profiles; private volatile UserPermissions permissions; private volatile SelfUser selfUser; private volatile List availableJavas; private volatile CompletableFuture> availableJavasFuture; + private volatile CompletableFuture processHardwareFuture; private final Map> pingFutures = new ConcurrentHashMap<>(); @Override @@ -76,6 +79,8 @@ private void doInit() throws Exception { allSettings = settingsManager.getConfig(); backendSettings = (BackendSettings) getUserSettings("backend", (k) -> new BackendSettings()); permissions = new ClientPermissions(); + ecKeyHolder = new ECKeyHolder(); + ecKeyHolder.readKeys(); DirBridge.dirUpdates = DirBridge.defaultUpdatesDir; } @@ -159,6 +164,9 @@ private void onAuthorize(SelfUser selfUser) { this.selfUser = selfUser; permissions = selfUser.getPermissions(); callback.onAuthorize(selfUser); + if(processHardwareFuture == null) { + processHardwareFuture = processHardware(); + } } @Override @@ -321,4 +329,33 @@ public CompletableFuture fetchTexture public CompletableFuture uploadTexture(String name, byte[] bytes, TextureUploadFeatureAPI.UploadSettings settings) { return LauncherAPIHolder.get().get(TextureUploadFeatureAPI.class).upload(name, bytes, settings); } + + public CompletableFuture processHardware() { + HardwareVerificationFeatureAPI featureAPI = LauncherAPIHolder.get().get(HardwareVerificationFeatureAPI.class); + if(featureAPI == null) { + return CompletableFuture.completedFuture(null); + } + return featureAPI.getSecurityInfo().thenCompose((response) -> { + if(!response.isRequired()) { + return CompletableFuture.completedFuture(null); + } + byte[] signature = SecurityHelper.sign(response.getSignData(), ecKeyHolder.privateKey); + return featureAPI.privateKeyVerification(ecKeyHolder.publicKey, signature); + }).thenCompose((response) -> { + switch (response.getHardwareCollectLevel()) { + case NONE -> { + return featureAPI.sendHardwareInfo(null, null); + } + case ONLY_STATISTIC -> { + HWIDProvider hwidProvider = new HWIDProvider(); + return featureAPI.sendHardwareInfo(hwidProvider.getStatisticData(), null); + } + case ALL -> { + HWIDProvider hwidProvider = new HWIDProvider(); + return featureAPI.sendHardwareInfo(hwidProvider.getStatisticData(), hwidProvider.getIdentifyData()); + } + } + return CompletableFuture.failedFuture(new UnsupportedOperationException()); + }); + } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/runtime/console/GetPublicKeyCommand.java b/Launcher/src/main/java/pro/gravit/launcher/runtime/console/GetPublicKeyCommand.java deleted file mode 100644 index 2d2e1ec1..00000000 --- a/Launcher/src/main/java/pro/gravit/launcher/runtime/console/GetPublicKeyCommand.java +++ /dev/null @@ -1,30 +0,0 @@ -package pro.gravit.launcher.runtime.console; - -import pro.gravit.launcher.runtime.LauncherEngine; -import pro.gravit.utils.command.Command; -import pro.gravit.utils.helper.LogHelper; - -import java.util.Base64; - -public class GetPublicKeyCommand extends Command { - private final LauncherEngine engine; - - public GetPublicKeyCommand(LauncherEngine engine) { - this.engine = engine; - } - - @Override - public String getArgsDescription() { - return "[]"; - } - - @Override - public String getUsageDescription() { - return "print public key in base64 format"; - } - - @Override - public void invoke(String... args) { - LogHelper.info("PublicKey: %s", Base64.getEncoder().encodeToString(engine.getClientPublicKey().getEncoded())); - } -} diff --git a/Launcher/src/main/java/pro/gravit/launcher/runtime/console/SignDataCommand.java b/Launcher/src/main/java/pro/gravit/launcher/runtime/console/SignDataCommand.java deleted file mode 100644 index 7be082d0..00000000 --- a/Launcher/src/main/java/pro/gravit/launcher/runtime/console/SignDataCommand.java +++ /dev/null @@ -1,34 +0,0 @@ -package pro.gravit.launcher.runtime.console; - -import pro.gravit.launcher.runtime.LauncherEngine; -import pro.gravit.utils.command.Command; -import pro.gravit.utils.helper.LogHelper; - -import java.util.Base64; - -public class SignDataCommand extends Command { - private final LauncherEngine engine; - - public SignDataCommand(LauncherEngine engine) { - this.engine = engine; - } - - @Override - public String getArgsDescription() { - return "[base64 data]"; - } - - @Override - public String getUsageDescription() { - return "sign any data"; - } - - @Override - public void invoke(String... args) throws Exception { - verifyArgs(args, 1); - byte[] data = Base64.getDecoder().decode(args[0]); - byte[] signature = engine.sign(data); - String base64 = Base64.getEncoder().encodeToString(signature); - LogHelper.info("Signature: %s", base64); - } -} diff --git a/Launcher/src/main/java/pro/gravit/launcher/runtime/utils/HWIDProvider.java b/Launcher/src/main/java/pro/gravit/launcher/runtime/utils/HWIDProvider.java index 9154a793..2028e0a1 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/runtime/utils/HWIDProvider.java +++ b/Launcher/src/main/java/pro/gravit/launcher/runtime/utils/HWIDProvider.java @@ -4,6 +4,8 @@ import oshi.hardware.*; import oshi.software.os.OperatingSystem; import pro.gravit.launcher.base.request.secure.HardwareReportRequest; +import pro.gravit.launcher.core.api.features.HardwareVerificationFeatureAPI; +import pro.gravit.utils.helper.JVMHelper; import java.util.List; @@ -104,6 +106,27 @@ public String getBaseboardSerialNumber() { return hardware.getComputerSystem().getBaseboard().getSerialNumber(); } + public HardwareVerificationFeatureAPI.HardwareStatisticData getStatisticData() { + return new HardwareVerificationFeatureAPI.HardwareStatisticData( + JVMHelper.ARCH.toHardwareFeatureArch(JVMHelper.ARCH_TYPE), + JVMHelper.OS.toHardwareFeatureOs(JVMHelper.OS_TYPE), + getTotalMemory(), + getProcessorLogicalCount(), + getProcessorPhysicalCount(), + getProcessorMaxFreq(), + isBattery(), + getGraphicCardName() + ); + } + + public HardwareVerificationFeatureAPI.HardwareIdentifyData getIdentifyData() { + return new HardwareVerificationFeatureAPI.HardwareIdentifyData( + getBaseboardSerialNumber(), + getHWDiskID(), + getDisplayID() + ); + } + public HardwareReportRequest.HardwareInfo getHardwareInfo(boolean needSerial) { HardwareReportRequest.HardwareInfo info = new HardwareReportRequest.HardwareInfo(); info.bitness = getBitness(); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/GetSecureLevelInfoRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/GetSecureLevelInfoRequestEvent.java index cd583424..36adbe71 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/GetSecureLevelInfoRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/GetSecureLevelInfoRequestEvent.java @@ -1,8 +1,9 @@ package pro.gravit.launcher.base.events.request; import pro.gravit.launcher.base.events.RequestEvent; +import pro.gravit.launcher.core.api.features.HardwareVerificationFeatureAPI; -public class GetSecureLevelInfoRequestEvent extends RequestEvent { +public class GetSecureLevelInfoRequestEvent extends RequestEvent implements HardwareVerificationFeatureAPI.SecurityLevelInfo { public final byte[] verifySecureKey; public boolean enabled; @@ -19,4 +20,14 @@ public GetSecureLevelInfoRequestEvent(byte[] verifySecureKey, boolean enabled) { public String getType() { return "getSecureLevelInfo"; } + + @Override + public boolean isRequired() { + return enabled; + } + + @Override + public byte[] getSignData() { + return verifySecureKey; + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/VerifySecureLevelKeyRequestEvent.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/VerifySecureLevelKeyRequestEvent.java index 754f3020..ac3b9de1 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/VerifySecureLevelKeyRequestEvent.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/events/request/VerifySecureLevelKeyRequestEvent.java @@ -2,8 +2,9 @@ import pro.gravit.launcher.base.events.ExtendedTokenRequestEvent; import pro.gravit.launcher.base.events.RequestEvent; +import pro.gravit.launcher.core.api.features.HardwareVerificationFeatureAPI; -public class VerifySecureLevelKeyRequestEvent extends RequestEvent implements ExtendedTokenRequestEvent { +public class VerifySecureLevelKeyRequestEvent extends RequestEvent implements ExtendedTokenRequestEvent, HardwareVerificationFeatureAPI.SecurityLevelVerification { public boolean needHardwareInfo; public boolean onlyStatisticInfo; public String extendedToken; @@ -42,4 +43,17 @@ public String getExtendedToken() { public long getExtendedTokenExpire() { return expire; } + + @Override + public HardwareCollectLevel getHardwareCollectLevel() { + if(needHardwareInfo) { + if(onlyStatisticInfo) { + return HardwareCollectLevel.ONLY_STATISTIC; + } else { + return HardwareCollectLevel.ALL; + } + } else { + return HardwareCollectLevel.NONE; + } + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestFeatureAPIImpl.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestFeatureAPIImpl.java index 0b9fe6a7..8d6621f8 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestFeatureAPIImpl.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/RequestFeatureAPIImpl.java @@ -1,20 +1,21 @@ package pro.gravit.launcher.base.request; import pro.gravit.launcher.base.Launcher; +import pro.gravit.launcher.base.events.request.VerifySecureLevelKeyRequestEvent; import pro.gravit.launcher.base.profiles.ClientProfile; import pro.gravit.launcher.base.request.auth.*; import pro.gravit.launcher.base.request.auth.password.*; import pro.gravit.launcher.base.request.cabinet.AssetUploadInfoRequest; import pro.gravit.launcher.base.request.cabinet.GetAssetUploadUrl; +import pro.gravit.launcher.base.request.secure.GetSecureLevelInfoRequest; +import pro.gravit.launcher.base.request.secure.HardwareReportRequest; +import pro.gravit.launcher.base.request.secure.VerifySecureLevelKeyRequest; import pro.gravit.launcher.base.request.update.ProfilesRequest; import pro.gravit.launcher.base.request.update.UpdateRequest; import pro.gravit.launcher.base.request.uuid.ProfileByUUIDRequest; import pro.gravit.launcher.base.request.uuid.ProfileByUsernameRequest; import pro.gravit.launcher.core.LauncherNetworkAPI; -import pro.gravit.launcher.core.api.features.AuthFeatureAPI; -import pro.gravit.launcher.core.api.features.TextureUploadFeatureAPI; -import pro.gravit.launcher.core.api.features.UserFeatureAPI; -import pro.gravit.launcher.core.api.features.ProfileFeatureAPI; +import pro.gravit.launcher.core.api.features.*; import pro.gravit.launcher.core.api.method.AuthMethodPassword; import pro.gravit.launcher.core.api.method.password.AuthChainPassword; import pro.gravit.launcher.core.api.method.password.AuthOAuthPassword; @@ -32,13 +33,14 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.security.PublicKey; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; -public class RequestFeatureAPIImpl implements AuthFeatureAPI, UserFeatureAPI, ProfileFeatureAPI, TextureUploadFeatureAPI { +public class RequestFeatureAPIImpl implements AuthFeatureAPI, UserFeatureAPI, ProfileFeatureAPI, TextureUploadFeatureAPI, HardwareVerificationFeatureAPI { private final RequestService request; private final String authId; private final HttpClient client = HttpClient.newBuilder().build(); @@ -249,6 +251,40 @@ public CompletableFuture upload(String name, byte[] bytes, UploadSettin }); } + @Override + public CompletableFuture getSecurityInfo() { + return request.request(new GetSecureLevelInfoRequest()).thenApply(response -> response); + } + + @Override + public CompletableFuture privateKeyVerification(PublicKey publicKey, byte[] signature) { + return request.request(new VerifySecureLevelKeyRequest(publicKey.getEncoded(), signature)).thenApply(response -> response); + } + + @Override + public CompletableFuture sendHardwareInfo(HardwareStatisticData statisticData, HardwareIdentifyData identifyData) { + if(statisticData == null && identifyData == null) { // Hardware info token special + return request.request(new HardwareReportRequest()).thenApply(response -> null); + } else { + var hardwareInfo = new HardwareReportRequest.HardwareInfo(); + if(statisticData != null) { + hardwareInfo.bitness = statisticData.arch() == Arch.X86 || statisticData.arch() == Arch.ARM32 ? 32 : 64; + hardwareInfo.totalMemory = statisticData.totalPhysicalMemory(); + hardwareInfo.logicalProcessors = statisticData.logicalProcessors(); + hardwareInfo.physicalProcessors = statisticData.physicalProcessors(); + hardwareInfo.processorMaxFreq = statisticData.processorMaxFreq(); + hardwareInfo.battery = statisticData.battery(); + hardwareInfo.graphicCard = statisticData.graphicCard(); + } + if(identifyData != null) { + hardwareInfo.hwDiskId = identifyData.persistentStorageId(); + hardwareInfo.displayId = identifyData.edid(); + hardwareInfo.baseboardSerialNumber = identifyData.baseboardSerialNumber(); + } + return request.request(new HardwareReportRequest(hardwareInfo)).thenApply(response -> null); + } + } + public record UpdateInfoData(HashedDir hdir, String url) implements ProfileFeatureAPI.UpdateInfo { @Override public HashedDir getHashedDir() { diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/secure/HardwareReportRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/secure/HardwareReportRequest.java index ebe1434f..ca9b80f1 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/secure/HardwareReportRequest.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/request/secure/HardwareReportRequest.java @@ -8,6 +8,13 @@ public class HardwareReportRequest extends Request { public HardwareInfo hardware; + public HardwareReportRequest() { + } + + public HardwareReportRequest(HardwareInfo hardware) { + this.hardware = hardware; + } + @Override public String getType() { return "hardwareReport"; diff --git a/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/HardwareVerificationFeatureAPI.java b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/HardwareVerificationFeatureAPI.java new file mode 100644 index 00000000..1ba1e218 --- /dev/null +++ b/LauncherCore/src/main/java/pro/gravit/launcher/core/api/features/HardwareVerificationFeatureAPI.java @@ -0,0 +1,57 @@ +package pro.gravit.launcher.core.api.features; + +import pro.gravit.utils.helper.JVMHelper; + +import java.security.PublicKey; +import java.util.concurrent.CompletableFuture; + +public interface HardwareVerificationFeatureAPI extends FeatureAPI { + CompletableFuture getSecurityInfo(); + CompletableFuture privateKeyVerification(PublicKey publicKey, byte[] signature); + CompletableFuture sendHardwareInfo(HardwareStatisticData statisticData, HardwareIdentifyData identifyData); + + + interface SecurityLevelInfo { + boolean isRequired(); + byte[] getSignData(); + } + interface SecurityLevelVerification { + HardwareCollectLevel getHardwareCollectLevel(); + + enum HardwareCollectLevel { + NONE, ONLY_STATISTIC, ALL + } + } + + record HardwareStatisticData(Arch arch, Os os, long totalPhysicalMemory, + int logicalProcessors, int physicalProcessors, + long processorMaxFreq, boolean battery, + String graphicCard) { + + } + + record HardwareIdentifyData(String baseboardSerialNumber, String persistentStorageId, + byte[] edid) { + + } + + enum Arch { + X86("x86"), X86_64("x86-64"), ARM64("arm64"), ARM32("arm32"); + + public final String name; + + Arch(String name) { + this.name = name; + } + } + + enum Os { + WINDOWS("windows"), LINUX("linux"), MACOS("macos"); + + public final String name; + + Os(String name) { + this.name = name; + } + } +} diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java index bf5ecbdf..002a8e2a 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java @@ -1,5 +1,7 @@ package pro.gravit.utils.helper; +import pro.gravit.launcher.core.api.features.HardwareVerificationFeatureAPI; + import java.lang.invoke.MethodHandles; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; @@ -56,7 +58,7 @@ public static int getBuild() { return Runtime.version().update(); } - public static String getNativeExtension(JVMHelper.OS OS_TYPE) { + public static String getNativeExtension(OS OS_TYPE) { return switch (OS_TYPE) { case MUSTDIE -> ".dll"; case LINUX -> ".so"; @@ -64,7 +66,7 @@ public static String getNativeExtension(JVMHelper.OS OS_TYPE) { }; } - public static String getNativePrefix(JVMHelper.OS OS_TYPE) { + public static String getNativePrefix(OS OS_TYPE) { return switch (OS_TYPE) { case LINUX, MACOSX -> "lib"; default -> ""; @@ -124,6 +126,15 @@ public enum ARCH { public final String name; + public static HardwareVerificationFeatureAPI.Arch toHardwareFeatureArch(ARCH arch) { + return switch (arch) { + case X86 -> HardwareVerificationFeatureAPI.Arch.X86; + case X86_64 -> HardwareVerificationFeatureAPI.Arch.X86_64; + case ARM64 -> HardwareVerificationFeatureAPI.Arch.ARM64; + case ARM32 -> HardwareVerificationFeatureAPI.Arch.ARM32; + }; + } + ARCH(String name) { this.name = name; } @@ -138,6 +149,14 @@ public enum OS { this.name = name; } + public static HardwareVerificationFeatureAPI.Os toHardwareFeatureOs(OS os) { + return switch (os) { + case MUSTDIE -> HardwareVerificationFeatureAPI.Os.WINDOWS; + case LINUX -> HardwareVerificationFeatureAPI.Os.LINUX; + case MACOSX -> HardwareVerificationFeatureAPI.Os.MACOS; + }; + } + public static OS byName(String name) { if (name.startsWith("Windows")) return MUSTDIE;