mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +03:00
[FEATURE] AuthSupportHardware
This commit is contained in:
parent
568852b951
commit
73c6c48f42
8 changed files with 262 additions and 12 deletions
|
@ -0,0 +1,13 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces;
|
||||
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
|
||||
public interface UserHardware {
|
||||
HardwareReportRequest.HardwareInfo getHardwareInfo();
|
||||
|
||||
byte[] getPublicKey();
|
||||
|
||||
String getId();
|
||||
|
||||
boolean isBanned();
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.provider;
|
||||
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.user.UserSupportHardware;
|
||||
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
||||
import pro.gravit.launchserver.helper.DamerauHelper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public interface AuthSupportHardware {
|
||||
UserHardware getHardwareInfoByPublicKey(byte[] publicKey);
|
||||
|
||||
UserHardware getHardwareInfoByData(HardwareReportRequest.HardwareInfo info);
|
||||
|
||||
UserHardware getHardwareInfoById(String id);
|
||||
|
||||
UserHardware createHardwareInfo(HardwareReportRequest.HardwareInfo info, byte[] publicKey);
|
||||
|
||||
void addPublicKeyToHardwareInfo(UserHardware hardware, byte[] publicKey);
|
||||
|
||||
List<User> getUsersByHardwareInfo(UserHardware hardware);
|
||||
|
||||
void banHardware(UserHardware hardware);
|
||||
|
||||
void unbanHardware(UserHardware hardware);
|
||||
|
||||
default UserSupportHardware fetchUserHardware(User user) {
|
||||
return (UserSupportHardware) user;
|
||||
}
|
||||
|
||||
default void normalizeHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo) {
|
||||
if (hardwareInfo.baseboardSerialNumber != null)
|
||||
hardwareInfo.baseboardSerialNumber = hardwareInfo.baseboardSerialNumber.trim();
|
||||
if (hardwareInfo.hwDiskId != null) hardwareInfo.hwDiskId = hardwareInfo.hwDiskId.trim();
|
||||
}
|
||||
|
||||
//Required normalize HardwareInfo
|
||||
default HWIDProvider.HardwareInfoCompareResult compareHardwareInfo(HardwareReportRequest.HardwareInfo first, HardwareReportRequest.HardwareInfo second) {
|
||||
HWIDProvider.HardwareInfoCompareResult result = new HWIDProvider.HardwareInfoCompareResult();
|
||||
if (first.hwDiskId == null || first.hwDiskId.isEmpty()) result.firstSpoofingLevel += 0.9;
|
||||
if (first.displayId == null || first.displayId.length < 4) result.firstSpoofingLevel += 0.3;
|
||||
if (first.baseboardSerialNumber == null || first.baseboardSerialNumber.trim().isEmpty())
|
||||
result.firstSpoofingLevel += 0.2;
|
||||
if (second.hwDiskId == null || second.hwDiskId.trim().isEmpty()) result.secondSpoofingLevel += 0.9;
|
||||
if (second.displayId == null || second.displayId.length < 4) result.secondSpoofingLevel += 0.3;
|
||||
if (second.baseboardSerialNumber == null || second.baseboardSerialNumber.trim().isEmpty())
|
||||
result.secondSpoofingLevel += 0.2;
|
||||
if (first.hwDiskId != null && second.hwDiskId != null) {
|
||||
int hwDIskIdRate = DamerauHelper.calculateDistance(first.hwDiskId.toLowerCase(), second.hwDiskId.toLowerCase());
|
||||
if (hwDIskIdRate == 0) // 100% compare
|
||||
{
|
||||
result.compareLevel += 0.99;
|
||||
} else if (hwDIskIdRate < 3) //Very small change
|
||||
{
|
||||
result.compareLevel += 0.85;
|
||||
} else if (hwDIskIdRate < (first.hwDiskId.length() + second.hwDiskId.length()) / 4) {
|
||||
double addLevel = hwDIskIdRate / ((double) (first.hwDiskId.length() + second.hwDiskId.length()) / 2.0);
|
||||
if (addLevel > 0.0 && addLevel < 0.85) result.compareLevel += addLevel;
|
||||
}
|
||||
}
|
||||
if (first.baseboardSerialNumber != null && second.baseboardSerialNumber != null) {
|
||||
int baseboardSerialRate = DamerauHelper.calculateDistance(first.baseboardSerialNumber.toLowerCase(), second.baseboardSerialNumber.toLowerCase());
|
||||
if (baseboardSerialRate == 0) // 100% compare
|
||||
{
|
||||
result.compareLevel += 0.3;
|
||||
} else if (baseboardSerialRate < 3) //Very small change
|
||||
{
|
||||
result.compareLevel += 0.15;
|
||||
}
|
||||
}
|
||||
if (first.displayId != null && second.displayId != null) {
|
||||
if (Arrays.equals(first.displayId, second.displayId)) {
|
||||
result.compareLevel += 0.75;
|
||||
}
|
||||
}
|
||||
//Check statistic info
|
||||
if (first.logicalProcessors == 0 || first.physicalProcessors == 0 || first.logicalProcessors < first.physicalProcessors) //WTF
|
||||
result.firstSpoofingLevel += 0.9;
|
||||
if (second.logicalProcessors == 0 || second.physicalProcessors == 0 || second.logicalProcessors < second.physicalProcessors) //WTF
|
||||
result.secondSpoofingLevel += 0.9;
|
||||
if (first.physicalProcessors == second.physicalProcessors && first.logicalProcessors == second.logicalProcessors)
|
||||
result.compareLevel += 0.05;
|
||||
if (first.battery != second.battery)
|
||||
result.compareLevel -= 0.05;
|
||||
if (first.processorMaxFreq == second.processorMaxFreq)
|
||||
result.compareLevel += 0.1;
|
||||
if (first.totalMemory == second.totalMemory)
|
||||
result.compareLevel += 0.1;
|
||||
if (Math.abs(first.totalMemory - second.totalMemory) < 32 * 1024)
|
||||
result.compareLevel += 0.05;
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package pro.gravit.launchserver.auth.core.interfaces.user;
|
||||
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
|
||||
public interface UserSupportHardware {
|
||||
UserHardware getHardware();
|
||||
}
|
|
@ -1,12 +1,18 @@
|
|||
package pro.gravit.launchserver.auth.protect;
|
||||
|
||||
import io.jsonwebtoken.JwtParser;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import pro.gravit.launcher.events.request.GetSecureLevelInfoRequestEvent;
|
||||
import pro.gravit.launcher.events.request.HardwareReportRequestEvent;
|
||||
import pro.gravit.launcher.events.request.VerifySecureLevelKeyRequestEvent;
|
||||
import pro.gravit.launcher.request.secure.HardwareReportRequest;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.Reconfigurable;
|
||||
import pro.gravit.launchserver.auth.AuthProviderPair;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.UserHardware;
|
||||
import pro.gravit.launchserver.auth.core.interfaces.provider.AuthSupportHardware;
|
||||
import pro.gravit.launchserver.auth.protect.hwid.HWIDException;
|
||||
import pro.gravit.launchserver.auth.protect.hwid.HWIDProvider;
|
||||
import pro.gravit.launchserver.auth.protect.interfaces.HardwareProtectHandler;
|
||||
|
@ -14,9 +20,12 @@
|
|||
import pro.gravit.launchserver.auth.protect.interfaces.SecureProtectHandler;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.auth.AuthResponse;
|
||||
import pro.gravit.launchserver.socket.response.auth.RestoreResponse;
|
||||
import pro.gravit.launchserver.socket.response.secure.HardwareReportResponse;
|
||||
import pro.gravit.utils.command.Command;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -49,7 +58,7 @@ public boolean allowGetSecureLevelInfo(Client client) {
|
|||
@Override
|
||||
public void onHardwareReport(HardwareReportResponse response, Client client) {
|
||||
if (!enableHardwareFeature) {
|
||||
response.sendResult(new HardwareReportRequestEvent());
|
||||
response.sendResult(new HardwareReportRequestEvent(createHardwareToken(client.username, response.hardware)));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
@ -57,36 +66,58 @@ public void onHardwareReport(HardwareReportResponse response, Client client) {
|
|||
response.sendError("Access denied");
|
||||
return;
|
||||
}
|
||||
provider.normalizeHardwareInfo(response.hardware);
|
||||
logger.debug("HardwareInfo received");
|
||||
boolean needCreate = !provider.addPublicKeyToHardwareInfo(response.hardware, client.trustLevel.publicKey, client);
|
||||
logger.debug("HardwareInfo needCreate: {}", needCreate ? "true" : "false");
|
||||
if (needCreate)
|
||||
provider.createHardwareInfo(response.hardware, client.trustLevel.publicKey, client);
|
||||
client.trustLevel.hardwareInfo = response.hardware;
|
||||
if (client.auth instanceof AuthSupportHardware) {
|
||||
AuthSupportHardware authSupportHardware = (AuthSupportHardware) client.auth;
|
||||
UserHardware hardware = authSupportHardware.getHardwareInfoByData(response.hardware);
|
||||
if (hardware == null) {
|
||||
hardware = authSupportHardware.createHardwareInfo(response.hardware, client.trustLevel.publicKey);
|
||||
} else {
|
||||
authSupportHardware.addPublicKeyToHardwareInfo(hardware, client.trustLevel.publicKey);
|
||||
}
|
||||
if (hardware.isBanned()) {
|
||||
throw new SecurityException("Your hardware banned");
|
||||
}
|
||||
client.trustLevel.hardwareInfo = hardware.getHardwareInfo();
|
||||
} else {
|
||||
provider.normalizeHardwareInfo(response.hardware);
|
||||
boolean needCreate = !provider.addPublicKeyToHardwareInfo(response.hardware, client.trustLevel.publicKey, client);
|
||||
logger.debug("HardwareInfo needCreate: {}", needCreate ? "true" : "false");
|
||||
if (needCreate)
|
||||
provider.createHardwareInfo(response.hardware, client.trustLevel.publicKey, client);
|
||||
client.trustLevel.hardwareInfo = response.hardware;
|
||||
}
|
||||
} catch (HWIDException e) {
|
||||
throw new SecurityException(e.getMessage());
|
||||
}
|
||||
response.sendResult(new HardwareReportRequestEvent());
|
||||
response.sendResult(new HardwareReportRequestEvent(createHardwareToken(client.username, response.hardware)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) {
|
||||
if (enableHardwareFeature) {
|
||||
if (provider == null) {
|
||||
if (client.isAuth && client.auth.core instanceof AuthSupportHardware) {
|
||||
UserHardware hardware = ((AuthSupportHardware) client.auth.core).getHardwareInfoByPublicKey(client.trustLevel.publicKey);
|
||||
if (hardware == null) //HWID not found?
|
||||
return new VerifySecureLevelKeyRequestEvent(true, false, createPublicKeyToken(client.username, client.trustLevel.publicKey));
|
||||
if (hardware.isBanned()) {
|
||||
throw new SecurityException("Your hardware banned");
|
||||
}
|
||||
client.trustLevel.hardwareInfo = hardware.getHardwareInfo();
|
||||
} else if (provider == null) {
|
||||
logger.warn("HWIDProvider null. HardwareInfo not checked!");
|
||||
} else {
|
||||
try {
|
||||
client.trustLevel.hardwareInfo = provider.findHardwareInfoByPublicKey(client.trustLevel.publicKey, client);
|
||||
if (client.trustLevel.hardwareInfo == null) //HWID not found?
|
||||
return new VerifySecureLevelKeyRequestEvent(true);
|
||||
return new VerifySecureLevelKeyRequestEvent(true, false, createPublicKeyToken(client.username, client.trustLevel.publicKey));
|
||||
} catch (HWIDException e) {
|
||||
throw new SecurityException(e.getMessage()); //Show banned message
|
||||
}
|
||||
}
|
||||
return new VerifySecureLevelKeyRequestEvent(false);
|
||||
return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey));
|
||||
}
|
||||
return new VerifySecureLevelKeyRequestEvent();
|
||||
return new VerifySecureLevelKeyRequestEvent(false, false, createPublicKeyToken(client.username, client.trustLevel.publicKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -114,4 +145,84 @@ public void close() {
|
|||
if (provider != null)
|
||||
provider.close();
|
||||
}
|
||||
|
||||
public String createHardwareToken(String username, HardwareReportRequest.HardwareInfo info) {
|
||||
return Jwts.builder()
|
||||
.setIssuer("LaunchSerer")
|
||||
.setSubject(username)
|
||||
.signWith(server.keyAgreementManager.ecdsaPrivateKey)
|
||||
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8))
|
||||
.claim("hardware", info)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public String createPublicKeyToken(String username, byte[] publicKey) {
|
||||
return Jwts.builder()
|
||||
.setIssuer("LaunchSerer")
|
||||
.setSubject(username)
|
||||
.signWith(server.keyAgreementManager.ecdsaPrivateKey)
|
||||
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8))
|
||||
.claim("publicKey", Base64.getEncoder().encode(publicKey))
|
||||
.compact();
|
||||
}
|
||||
|
||||
public static class HardwareInfoTokenVerifier implements RestoreResponse.ExtendedTokenProvider {
|
||||
private transient final LaunchServer server;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
private final JwtParser parser;
|
||||
|
||||
public HardwareInfoTokenVerifier(LaunchServer server) {
|
||||
this.server = server;
|
||||
this.parser = Jwts.parserBuilder()
|
||||
.requireIssuer("LaunchServer")
|
||||
.setSigningKey(server.keyAgreementManager.ecdsaPublicKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(Client client, AuthProviderPair pair, String extendedToken) {
|
||||
try {
|
||||
var parse = parser.parseClaimsJws(extendedToken);
|
||||
HardwareReportRequest.HardwareInfo hardwareInfo = parse.getBody().get("hardware", HardwareReportRequest.HardwareInfo.class);
|
||||
if (hardwareInfo == null) return false;
|
||||
if (client.trustLevel == null) client.trustLevel = new Client.TrustLevel();
|
||||
client.trustLevel.hardwareInfo = hardwareInfo;
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
logger.error("Hardware JWT error", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PublicKeyTokenVerifier implements RestoreResponse.ExtendedTokenProvider {
|
||||
private transient final LaunchServer server;
|
||||
private transient final Logger logger = LogManager.getLogger();
|
||||
private final JwtParser parser;
|
||||
|
||||
public PublicKeyTokenVerifier(LaunchServer server) {
|
||||
this.server = server;
|
||||
this.parser = Jwts.parserBuilder()
|
||||
.requireIssuer("LaunchServer")
|
||||
.setSigningKey(server.keyAgreementManager.ecdsaPublicKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(Client client, AuthProviderPair pair, String extendedToken) {
|
||||
try {
|
||||
var parse = parser.parseClaimsJws(extendedToken);
|
||||
String publicKey = parse.getBody().get("publicKey", String.class);
|
||||
if (publicKey == null) return false;
|
||||
if (client.trustLevel == null) client.trustLevel = new Client.TrustLevel();
|
||||
client.trustLevel.publicKey = Base64.getDecoder().decode(publicKey);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
logger.error("Public Key JWT error", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import pro.gravit.launchserver.auth.core.AuthCoreProvider;
|
||||
import pro.gravit.launchserver.auth.core.User;
|
||||
import pro.gravit.launchserver.auth.core.UserSession;
|
||||
import pro.gravit.launchserver.auth.protect.AdvancedProtectHandler;
|
||||
import pro.gravit.launchserver.socket.Client;
|
||||
import pro.gravit.launchserver.socket.response.SimpleResponse;
|
||||
import pro.gravit.launchserver.socket.response.update.LauncherResponse;
|
||||
|
@ -29,6 +30,8 @@ public class RestoreResponse extends SimpleResponse {
|
|||
public static void registerProviders(LaunchServer server) {
|
||||
if (!registeredProviders) {
|
||||
providers.put(LauncherRequestEvent.LAUNCHER_EXTENDED_TOKEN_NAME, new LauncherResponse.LauncherTokenVerifier(server));
|
||||
providers.put("publicKey", new AdvancedProtectHandler.PublicKeyTokenVerifier(server));
|
||||
providers.put("hardware", new AdvancedProtectHandler.HardwareInfoTokenVerifier(server));
|
||||
registeredProviders = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@ public String getType() {
|
|||
|
||||
@Override
|
||||
public void execute(ChannelHandlerContext ctx, Client client) {
|
||||
if (client.trustLevel == null || client.trustLevel.publicKey == null) {
|
||||
sendError("Invalid request");
|
||||
return;
|
||||
}
|
||||
if (server.config.protectHandler instanceof HardwareProtectHandler) {
|
||||
try {
|
||||
((HardwareProtectHandler) server.config.protectHandler).onHardwareReport(this, client);
|
||||
|
|
|
@ -3,6 +3,15 @@
|
|||
import pro.gravit.launcher.events.RequestEvent;
|
||||
|
||||
public class HardwareReportRequestEvent extends RequestEvent {
|
||||
public String extendedToken;
|
||||
|
||||
public HardwareReportRequestEvent() {
|
||||
}
|
||||
|
||||
public HardwareReportRequestEvent(String extendedToken) {
|
||||
this.extendedToken = extendedToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "hardwareReport";
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
public class VerifySecureLevelKeyRequestEvent extends RequestEvent {
|
||||
public boolean needHardwareInfo;
|
||||
public boolean onlyStatisticInfo;
|
||||
public String extendedToken;
|
||||
|
||||
public VerifySecureLevelKeyRequestEvent() {
|
||||
}
|
||||
|
@ -13,6 +14,12 @@ public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo) {
|
|||
this.needHardwareInfo = needHardwareInfo;
|
||||
}
|
||||
|
||||
public VerifySecureLevelKeyRequestEvent(boolean needHardwareInfo, boolean onlyStatisticInfo, String extendedToken) {
|
||||
this.needHardwareInfo = needHardwareInfo;
|
||||
this.onlyStatisticInfo = onlyStatisticInfo;
|
||||
this.extendedToken = extendedToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "verifySecureLevelKey";
|
||||
|
|
Loading…
Reference in a new issue