[ANY] IDEA Reformat

This commit is contained in:
Gravit 2020-09-25 22:48:33 +07:00
parent 8ce5b4179c
commit 9766cd69e5
No known key found for this signature in database
GPG key ID: 98A079490768CCE5
50 changed files with 322 additions and 411 deletions

View file

@ -388,7 +388,7 @@ public void syncProfilesDir() throws IOException {
// Sort and set new profiles // Sort and set new profiles
newProfies.sort(Comparator.comparing(a -> a)); newProfies.sort(Comparator.comparing(a -> a));
profilesList = Collections.unmodifiableList(newProfies); profilesList = Collections.unmodifiableList(newProfies);
if(pingServerManager != null) if (pingServerManager != null)
pingServerManager.syncServers(); pingServerManager.syncServers();
} }

View file

@ -171,9 +171,8 @@ private static InsnList serializeValue(Object value) {
value.getClass())); value.getClass()));
} }
public static boolean isSerializableValue(Object value) public static boolean isSerializableValue(Object value) {
{ if (value == null) return true;
if(value == null) return true;
if (primitiveLDCClasses.contains(value.getClass())) return true; if (primitiveLDCClasses.contains(value.getClass())) return true;
for (Map.Entry<Class<?>, Serializer<?>> serializerEntry : serializers.entrySet()) { for (Map.Entry<Class<?>, Serializer<?>> serializerEntry : serializers.entrySet()) {
if (serializerEntry.getKey().isInstance(value)) { if (serializerEntry.getKey().isInstance(value)) {

View file

@ -51,6 +51,7 @@ public EntryRequestByUsername(String username, String apiKey) {
public static class EntryRequestByUUID { public static class EntryRequestByUUID {
public final UUID uuid; public final UUID uuid;
public final String apiKey; public final String apiKey;
public EntryRequestByUUID(UUID uuid, String apiKey) { public EntryRequestByUUID(UUID uuid, String apiKey) {
this.uuid = uuid; this.uuid = uuid;
this.apiKey = apiKey; this.apiKey = apiKey;

View file

@ -46,14 +46,12 @@ public boolean allowGetSecureLevelInfo(Client client) {
@Override @Override
public void onHardwareReport(HardwareReportResponse response, Client client) { public void onHardwareReport(HardwareReportResponse response, Client client) {
if(!enableHardwareFeature) if (!enableHardwareFeature) {
{
response.sendResult(new HardwareReportRequestEvent()); response.sendResult(new HardwareReportRequestEvent());
return; return;
} }
try { try {
if(!client.isAuth || client.trustLevel == null || client.trustLevel.publicKey == null) if (!client.isAuth || client.trustLevel == null || client.trustLevel.publicKey == null) {
{
response.sendError("Access denied"); response.sendError("Access denied");
return; return;
} }
@ -61,7 +59,7 @@ public void onHardwareReport(HardwareReportResponse response, Client client) {
LogHelper.debug("[HardwareInfo] HardwareInfo received"); LogHelper.debug("[HardwareInfo] HardwareInfo received");
boolean needCreate = !provider.addPublicKeyToHardwareInfo(response.hardware, client.trustLevel.publicKey, client); boolean needCreate = !provider.addPublicKeyToHardwareInfo(response.hardware, client.trustLevel.publicKey, client);
LogHelper.debug("[HardwareInfo] HardwareInfo needCreate: %s", needCreate ? "true" : "false"); LogHelper.debug("[HardwareInfo] HardwareInfo needCreate: %s", needCreate ? "true" : "false");
if(needCreate) if (needCreate)
provider.createHardwareInfo(response.hardware, client.trustLevel.publicKey, client); provider.createHardwareInfo(response.hardware, client.trustLevel.publicKey, client);
client.trustLevel.hardwareInfo = response.hardware; client.trustLevel.hardwareInfo = response.hardware;
} catch (HWIDException e) { } catch (HWIDException e) {
@ -72,17 +70,13 @@ public void onHardwareReport(HardwareReportResponse response, Client client) {
@Override @Override
public VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) { public VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) {
if(enableHardwareFeature) if (enableHardwareFeature) {
{ if (provider == null) {
if(provider == null)
{
LogHelper.warning("HWIDProvider null. HardwareInfo not checked!"); LogHelper.warning("HWIDProvider null. HardwareInfo not checked!");
} } else {
else
{
try { try {
client.trustLevel.hardwareInfo = provider.findHardwareInfoByPublicKey(client.trustLevel.publicKey, client); client.trustLevel.hardwareInfo = provider.findHardwareInfoByPublicKey(client.trustLevel.publicKey, client);
if(client.trustLevel.hardwareInfo == null) //HWID not found? if (client.trustLevel.hardwareInfo == null) //HWID not found?
return new VerifySecureLevelKeyRequestEvent(true); return new VerifySecureLevelKeyRequestEvent(true);
} catch (HWIDException e) { } catch (HWIDException e) {
throw new SecurityException(e.getMessage()); //Show banned message throw new SecurityException(e.getMessage()); //Show banned message
@ -96,8 +90,7 @@ public VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) {
@Override @Override
public Map<String, Command> getCommands() { public Map<String, Command> getCommands() {
Map<String, Command> commands = new HashMap<>(); Map<String, Command> commands = new HashMap<>();
if(provider instanceof Reconfigurable) if (provider instanceof Reconfigurable) {
{
commands.putAll(((Reconfigurable) provider).getCommands()); commands.putAll(((Reconfigurable) provider).getCommands());
} }
return commands; return commands;
@ -110,13 +103,13 @@ public boolean onJoinServer(String serverID, String username, Client client) {
@Override @Override
public void init(LaunchServer server) { public void init(LaunchServer server) {
if(provider != null) if (provider != null)
provider.init(server); provider.init(server);
} }
@Override @Override
public void close() { public void close() {
if(provider != null) if (provider != null)
provider.close(); provider.close();
} }
} }

View file

@ -22,13 +22,11 @@ public static void registerHandlers() {
public abstract void checkLaunchServerLicense(); //Выдает SecurityException при ошибке проверки лицензии public abstract void checkLaunchServerLicense(); //Выдает SecurityException при ошибке проверки лицензии
public void init(LaunchServer server) public void init(LaunchServer server) {
{
} }
public void close() public void close() {
{
} }
//public abstract //public abstract

View file

@ -13,108 +13,102 @@
public abstract class HWIDProvider { public abstract class HWIDProvider {
public static final ProviderMap<HWIDProvider> providers = new ProviderMap<>("HWIDProvider"); public static final ProviderMap<HWIDProvider> providers = new ProviderMap<>("HWIDProvider");
private static boolean registredProv = false; private static boolean registredProv = false;
public static void registerProviders() { public static void registerProviders() {
if(!registredProv) if (!registredProv) {
{
providers.register("memory", MemoryHWIDProvider.class); providers.register("memory", MemoryHWIDProvider.class);
providers.register("mysql", MysqlHWIDProvider.class); providers.register("mysql", MysqlHWIDProvider.class);
providers.register("json", JsonHWIDProvider.class); providers.register("json", JsonHWIDProvider.class);
registredProv = true; registredProv = true;
} }
} }
public abstract HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] publicKey, Client client) throws HWIDException; public abstract HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] publicKey, Client client) throws HWIDException;
public abstract void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException; public abstract void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException;
public abstract boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException; public abstract boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException;
public void normalizeHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo) public void normalizeHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo) {
{ if (hardwareInfo.baseboardSerialNumber != null)
if(hardwareInfo.baseboardSerialNumber != null) hardwareInfo.baseboardSerialNumber = hardwareInfo.baseboardSerialNumber.trim(); hardwareInfo.baseboardSerialNumber = hardwareInfo.baseboardSerialNumber.trim();
if(hardwareInfo.hwDiskId != null) hardwareInfo.hwDiskId = hardwareInfo.hwDiskId.trim(); if (hardwareInfo.hwDiskId != null) hardwareInfo.hwDiskId = hardwareInfo.hwDiskId.trim();
} }
public static class HardwareInfoCompareResult
{ public static class HardwareInfoCompareResult {
public double firstSpoofingLevel = 0.0; public double firstSpoofingLevel = 0.0;
public double secondSpoofingLevel = 0.0; public double secondSpoofingLevel = 0.0;
public double compareLevel; public double compareLevel;
} }
//Required normalize HardwareInfo //Required normalize HardwareInfo
public HardwareInfoCompareResult compareHardwareInfo(HardwareReportRequest.HardwareInfo first, HardwareReportRequest.HardwareInfo second) public HardwareInfoCompareResult compareHardwareInfo(HardwareReportRequest.HardwareInfo first, HardwareReportRequest.HardwareInfo second) {
{
HardwareInfoCompareResult result = new HardwareInfoCompareResult(); HardwareInfoCompareResult result = new HardwareInfoCompareResult();
if(first.hwDiskId == null || first.hwDiskId.isEmpty()) result.firstSpoofingLevel += 0.9; 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.displayId == null || first.displayId.length < 4) result.firstSpoofingLevel += 0.3;
if(first.baseboardSerialNumber == null || first.baseboardSerialNumber.trim().isEmpty()) result.firstSpoofingLevel += 0.2; if (first.baseboardSerialNumber == null || first.baseboardSerialNumber.trim().isEmpty())
if(second.hwDiskId == null || second.hwDiskId.trim().isEmpty()) result.secondSpoofingLevel += 0.9; result.firstSpoofingLevel += 0.2;
if(second.displayId == null || second.displayId.length < 4) result.secondSpoofingLevel += 0.3; if (second.hwDiskId == null || second.hwDiskId.trim().isEmpty()) result.secondSpoofingLevel += 0.9;
if(second.baseboardSerialNumber == null || second.baseboardSerialNumber.trim().isEmpty()) result.secondSpoofingLevel += 0.2; if (second.displayId == null || second.displayId.length < 4) result.secondSpoofingLevel += 0.3;
if(first.hwDiskId != null && second.hwDiskId != null) 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()); int hwDIskIdRate = DamerauHelper.calculateDistance(first.hwDiskId.toLowerCase(), second.hwDiskId.toLowerCase());
if(hwDIskIdRate == 0) // 100% compare if (hwDIskIdRate == 0) // 100% compare
{ {
result.compareLevel += 0.99; result.compareLevel += 0.99;
} } else if (hwDIskIdRate < 3) //Very small change
else if(hwDIskIdRate < 3) //Very small change
{ {
result.compareLevel += 0.85; result.compareLevel += 0.85;
} } else if (hwDIskIdRate < (first.hwDiskId.length() + second.hwDiskId.length()) / 4) {
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;
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) if (first.baseboardSerialNumber != null && second.baseboardSerialNumber != null) {
{
int baseboardSerialRate = DamerauHelper.calculateDistance(first.baseboardSerialNumber.toLowerCase(), second.baseboardSerialNumber.toLowerCase()); int baseboardSerialRate = DamerauHelper.calculateDistance(first.baseboardSerialNumber.toLowerCase(), second.baseboardSerialNumber.toLowerCase());
if(baseboardSerialRate == 0) // 100% compare if (baseboardSerialRate == 0) // 100% compare
{ {
result.compareLevel += 0.3; result.compareLevel += 0.3;
} } else if (baseboardSerialRate < 3) //Very small change
else if(baseboardSerialRate < 3) //Very small change
{ {
result.compareLevel += 0.15; result.compareLevel += 0.15;
} }
} }
if(first.displayId != null && second.displayId != null) if (first.displayId != null && second.displayId != null) {
{ if (Arrays.equals(first.displayId, second.displayId)) {
if(Arrays.equals(first.displayId, second.displayId))
{
result.compareLevel += 0.75; result.compareLevel += 0.75;
} }
} }
//Check statistic info //Check statistic info
if(first.logicalProcessors == 0 || first.physicalProcessors == 0 || first.logicalProcessors < first.physicalProcessors) //WTF if (first.logicalProcessors == 0 || first.physicalProcessors == 0 || first.logicalProcessors < first.physicalProcessors) //WTF
result.firstSpoofingLevel += 0.9; result.firstSpoofingLevel += 0.9;
if(second.logicalProcessors == 0 || second.physicalProcessors == 0 || second.logicalProcessors < second.physicalProcessors) //WTF if (second.logicalProcessors == 0 || second.physicalProcessors == 0 || second.logicalProcessors < second.physicalProcessors) //WTF
result.secondSpoofingLevel += 0.9; result.secondSpoofingLevel += 0.9;
if(first.physicalProcessors == second.physicalProcessors && first.logicalProcessors == second.logicalProcessors) if (first.physicalProcessors == second.physicalProcessors && first.logicalProcessors == second.logicalProcessors)
result.compareLevel += 0.05; result.compareLevel += 0.05;
if(first.battery != second.battery) if (first.battery != second.battery)
result.compareLevel -= 0.05; result.compareLevel -= 0.05;
if(first.processorMaxFreq == second.processorMaxFreq) if (first.processorMaxFreq == second.processorMaxFreq)
result.compareLevel += 0.1; result.compareLevel += 0.1;
if(first.totalMemory == second.totalMemory) if (first.totalMemory == second.totalMemory)
result.compareLevel += 0.1; result.compareLevel += 0.1;
if(Math.abs(first.totalMemory - second.totalMemory) < 32*1024) if (Math.abs(first.totalMemory - second.totalMemory) < 32 * 1024)
result.compareLevel += 0.05; result.compareLevel += 0.05;
return result; return result;
} }
protected void printHardwareInfo(LogHelper.Level logLevel, HardwareReportRequest.HardwareInfo info) protected void printHardwareInfo(LogHelper.Level logLevel, HardwareReportRequest.HardwareInfo info) {
{ LogHelper.log(logLevel, String.format("[HardwareInfo] Processor: logical %d | physical %d | freq %d | bitness %d", info.logicalProcessors, info.physicalProcessors, info.processorMaxFreq, info.bitness), false);
LogHelper.log(logLevel, String.format("[HardwareInfo] Processor: logical %d | physical %d | freq %d | bitness %d", info.logicalProcessors, info.physicalProcessors, info.processorMaxFreq, info.bitness) , false); LogHelper.log(logLevel, String.format("[HardwareInfo] Memory max: %d | battery %s", info.totalMemory, info.battery ? "true" : "false"), false);
LogHelper.log(logLevel, String.format("[HardwareInfo] Memory max: %d | battery %s", info.totalMemory, info.battery ? "true" : "false") , false); LogHelper.log(logLevel, String.format("[HardwareInfo] HWDiskID %s | baseboardSerialNumber %s | displayId hash: %s", info.hwDiskId, info.baseboardSerialNumber, SecurityHelper.toHex(SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, info.displayId))), false);
LogHelper.log(logLevel, String.format("[HardwareInfo] HWDiskID %s | baseboardSerialNumber %s | displayId hash: %s", info.hwDiskId, info.baseboardSerialNumber, SecurityHelper.toHex(SecurityHelper.digest(SecurityHelper.DigestAlgorithm.MD5, info.displayId))) , false);
} }
public void init(LaunchServer server) public void init(LaunchServer server) {
{
} }
public void close() public void close() {
{
} }
} }

View file

@ -12,15 +12,18 @@ public class JsonHWIDProvider extends HWIDProvider {
public URL createHardwareInfoRequest; public URL createHardwareInfoRequest;
public URL addPublicKeyToHardwareInfoRequest; public URL addPublicKeyToHardwareInfoRequest;
public String apiKey; public String apiKey;
public static class RequestFind { public static class RequestFind {
public byte[] publicKey; public byte[] publicKey;
public Client client; public Client client;
public String apiKey; public String apiKey;
} }
public static class ResultFind { public static class ResultFind {
public String error; public String error;
public HardwareReportRequest.HardwareInfo info; public HardwareReportRequest.HardwareInfo info;
} }
@Override @Override
public HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] publicKey, Client client) throws HWIDException { public HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] publicKey, Client client) throws HWIDException {
try { try {
@ -33,19 +36,22 @@ public HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] pub
return r.info; return r.info;
} catch (HWIDException t) { } catch (HWIDException t) {
throw t; throw t;
} catch (Throwable t) { } catch (Throwable t) {
throw new HWIDException(t); throw new HWIDException(t);
} }
} }
public static class RequestCreate { public static class RequestCreate {
public byte[] publicKey; public byte[] publicKey;
public Client client; public Client client;
public HardwareReportRequest.HardwareInfo hardwareInfo; public HardwareReportRequest.HardwareInfo hardwareInfo;
public String apiKey; public String apiKey;
} }
public static class ResultCreate { public static class ResultCreate {
public String error; public String error;
} }
@Override @Override
public void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException { public void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException {
try { try {
@ -58,20 +64,23 @@ public void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo,
if (r.error != null) throw new HWIDException(r.error); if (r.error != null) throw new HWIDException(r.error);
} catch (HWIDException t) { } catch (HWIDException t) {
throw t; throw t;
} catch (Throwable t) { } catch (Throwable t) {
throw new HWIDException(t); throw new HWIDException(t);
} }
} }
public static class RequestAddKey { public static class RequestAddKey {
public byte[] publicKey; public byte[] publicKey;
public Client client; public Client client;
public HardwareReportRequest.HardwareInfo hardwareInfo; public HardwareReportRequest.HardwareInfo hardwareInfo;
public String apiKey; public String apiKey;
} }
public static class ResultAddKey { public static class ResultAddKey {
public String error; public String error;
public boolean success; public boolean success;
} }
@Override @Override
public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException { public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException {
try { try {
@ -85,7 +94,7 @@ public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo har
return r.success; return r.success;
} catch (HWIDException t) { } catch (HWIDException t) {
throw t; throw t;
} catch (Throwable t) { } catch (Throwable t) {
throw new HWIDException(t); throw new HWIDException(t);
} }
} }

View file

@ -24,8 +24,7 @@ public Map<String, Command> getCommands() {
commands.put("hardwarelist", new SubCommand() { commands.put("hardwarelist", new SubCommand() {
@Override @Override
public void invoke(String... args) throws Exception { public void invoke(String... args) throws Exception {
for(MemoryHWIDEntity e : db) for (MemoryHWIDEntity e : db) {
{
printHardwareInfo(LogHelper.Level.INFO, e.hardware); printHardwareInfo(LogHelper.Level.INFO, e.hardware);
LogHelper.info("ID %d banned %s", e.id, e.banned ? "true" : "false"); LogHelper.info("ID %d banned %s", e.id, e.banned ? "true" : "false");
LogHelper.info("PublicKey Hash: %s", SecurityHelper.toHex(SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA1, e.publicKey))); LogHelper.info("PublicKey Hash: %s", SecurityHelper.toHex(SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA1, e.publicKey)));
@ -37,10 +36,8 @@ public void invoke(String... args) throws Exception {
public void invoke(String... args) throws Exception { public void invoke(String... args) throws Exception {
verifyArgs(args, 1); verifyArgs(args, 1);
long id = Long.parseLong(args[0]); long id = Long.parseLong(args[0]);
for(MemoryHWIDEntity e : db) for (MemoryHWIDEntity e : db) {
{ if (e.id == id) {
if(e.id == id)
{
e.banned = true; e.banned = true;
LogHelper.info("HardwareID %d banned", e.id); LogHelper.info("HardwareID %d banned", e.id);
} }
@ -50,8 +47,7 @@ public void invoke(String... args) throws Exception {
return commands; return commands;
} }
static class MemoryHWIDEntity static class MemoryHWIDEntity {
{
public HardwareReportRequest.HardwareInfo hardware; public HardwareReportRequest.HardwareInfo hardware;
public byte[] publicKey; public byte[] publicKey;
public boolean banned; public boolean banned;
@ -63,14 +59,14 @@ public MemoryHWIDEntity(HardwareReportRequest.HardwareInfo hardware, byte[] publ
this.id = SecurityHelper.newRandom().nextLong(); this.id = SecurityHelper.newRandom().nextLong();
} }
} }
public Set<MemoryHWIDEntity> db = ConcurrentHashMap.newKeySet(); public Set<MemoryHWIDEntity> db = ConcurrentHashMap.newKeySet();
@Override @Override
public HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] publicKey, Client client) throws HWIDException { public HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] publicKey, Client client) throws HWIDException {
for(MemoryHWIDEntity e : db) { for (MemoryHWIDEntity e : db) {
if(Arrays.equals(e.publicKey, publicKey)) if (Arrays.equals(e.publicKey, publicKey)) {
{ if (e.banned) throw new HWIDException("You HWID banned");
if(e.banned) throw new HWIDException("You HWID banned");
return e.hardware; return e.hardware;
} }
} }
@ -85,17 +81,15 @@ public void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo,
@Override @Override
public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException { public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException {
boolean isAlreadyWarning = false; boolean isAlreadyWarning = false;
for(MemoryHWIDEntity e : db) { for (MemoryHWIDEntity e : db) {
HardwareInfoCompareResult result = compareHardwareInfo(e.hardware, hardwareInfo); HardwareInfoCompareResult result = compareHardwareInfo(e.hardware, hardwareInfo);
if(warningSpoofingLevel > 0 && result.firstSpoofingLevel > warningSpoofingLevel && !isAlreadyWarning) if (warningSpoofingLevel > 0 && result.firstSpoofingLevel > warningSpoofingLevel && !isAlreadyWarning) {
{
LogHelper.warning("HardwareInfo spoofing level too high: %d", result.firstSpoofingLevel); LogHelper.warning("HardwareInfo spoofing level too high: %d", result.firstSpoofingLevel);
isAlreadyWarning = true; isAlreadyWarning = true;
} }
if(result.compareLevel > criticalCompareLevel) if (result.compareLevel > criticalCompareLevel) {
{
LogHelper.debug("HardwareInfo publicKey change: compareLevel %d", result.compareLevel); LogHelper.debug("HardwareInfo publicKey change: compareLevel %d", result.compareLevel);
if(e.banned) throw new HWIDException("You HWID banned"); if (e.banned) throw new HWIDException("You HWID banned");
e.publicKey = publicKey; e.publicKey = publicKey;
return true; return true;
} }

View file

@ -36,33 +36,28 @@ public void init(LaunchServer server) {
sqlCreateHardware = String.format("INSERT INTO `%s` (`publickey`, `hwDiskId`, `baseboardSerialNumber`, `displayId`, `bitness`, `totalMemory`, `logicalProcessors`, `physicalProcessors`, `processorMaxFreq`, `battery`, `banned`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '0')", tableHWID); sqlCreateHardware = String.format("INSERT INTO `%s` (`publickey`, `hwDiskId`, `baseboardSerialNumber`, `displayId`, `bitness`, `totalMemory`, `logicalProcessors`, `physicalProcessors`, `processorMaxFreq`, `battery`, `banned`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '0')", tableHWID);
sqlCreateHWIDLog = String.format("INSERT INTO %s (`hwidId`, `newPublicKey`) VALUES (?, ?)", tableHWIDLog); sqlCreateHWIDLog = String.format("INSERT INTO %s (`hwidId`, `newPublicKey`) VALUES (?, ?)", tableHWIDLog);
sqlUpdateHardware = String.format("UPDATE %s SET `publicKey` = ? WHERE `id` = ?", tableHWID); sqlUpdateHardware = String.format("UPDATE %s SET `publicKey` = ? WHERE `id` = ?", tableHWID);
if(tableUsers != null && usersHWIDColumn != null && usersNameColumn != null) { if (tableUsers != null && usersHWIDColumn != null && usersNameColumn != null) {
sqlUpdateUsers = String.format("UPDATE %s SET `%s` = ? WHERE `%s` = ?", tableUsers, usersHWIDColumn, usersNameColumn); sqlUpdateUsers = String.format("UPDATE %s SET `%s` = ? WHERE `%s` = ?", tableUsers, usersHWIDColumn, usersNameColumn);
} } else {
else {
LogHelper.warning("[MysqlHWIDProvider] Link to users table not configured"); LogHelper.warning("[MysqlHWIDProvider] Link to users table not configured");
} }
} }
@Override @Override
public HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] publicKey, Client client) throws HWIDException { public HardwareReportRequest.HardwareInfo findHardwareInfoByPublicKey(byte[] publicKey, Client client) throws HWIDException {
try(Connection connection = mySQLHolder.getConnection()) try (Connection connection = mySQLHolder.getConnection()) {
{
PreparedStatement s = connection.prepareStatement(sqlFindByPublicKey); PreparedStatement s = connection.prepareStatement(sqlFindByPublicKey);
s.setBlob(1, new ByteArrayInputStream(publicKey)); s.setBlob(1, new ByteArrayInputStream(publicKey));
ResultSet set = s.executeQuery(); ResultSet set = s.executeQuery();
if(set.next()) if (set.next()) {
{ if (set.getBoolean(11)) //isBanned
if(set.getBoolean(11)) //isBanned
{ {
throw new SecurityException("You HWID banned"); throw new SecurityException("You HWID banned");
} }
long id = set.getLong(10); long id = set.getLong(10);
setUserHardwareId(connection, client.username, id); setUserHardwareId(connection, client.username, id);
return fetchHardwareInfo(set); return fetchHardwareInfo(set);
} } else {
else
{
return null; return null;
} }
} catch (SQLException | IOException throwables) { } catch (SQLException | IOException throwables) {
@ -88,8 +83,7 @@ private HardwareReportRequest.HardwareInfo fetchHardwareInfo(ResultSet set) thro
@Override @Override
public void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException { public void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException {
try(Connection connection = mySQLHolder.getConnection()) try (Connection connection = mySQLHolder.getConnection()) {
{
PreparedStatement s = connection.prepareStatement(sqlCreateHardware, Statement.RETURN_GENERATED_KEYS); PreparedStatement s = connection.prepareStatement(sqlCreateHardware, Statement.RETURN_GENERATED_KEYS);
s.setBlob(1, new ByteArrayInputStream(publicKey)); s.setBlob(1, new ByteArrayInputStream(publicKey));
s.setString(2, hardwareInfo.hwDiskId); s.setString(2, hardwareInfo.hwDiskId);
@ -116,18 +110,15 @@ public void createHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo,
@Override @Override
public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException { public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo hardwareInfo, byte[] publicKey, Client client) throws HWIDException {
try(Connection connection = mySQLHolder.getConnection()) try (Connection connection = mySQLHolder.getConnection()) {
{
PreparedStatement s = connection.prepareStatement(sqlFindByHardware); PreparedStatement s = connection.prepareStatement(sqlFindByHardware);
ResultSet set = s.executeQuery(); ResultSet set = s.executeQuery();
while(set.next()) while (set.next()) {
{
HardwareReportRequest.HardwareInfo hw = fetchHardwareInfo(set); HardwareReportRequest.HardwareInfo hw = fetchHardwareInfo(set);
long id = set.getLong(10); long id = set.getLong(10);
HardwareInfoCompareResult result = compareHardwareInfo(hw, hardwareInfo); HardwareInfoCompareResult result = compareHardwareInfo(hw, hardwareInfo);
if(result.compareLevel > criticalCompareLevel) if (result.compareLevel > criticalCompareLevel) {
{ if (set.getBoolean(11)) //isBanned
if(set.getBoolean(11)) //isBanned
{ {
throw new SecurityException("You HWID banned"); throw new SecurityException("You HWID banned");
} }
@ -137,27 +128,29 @@ public boolean addPublicKeyToHardwareInfo(HardwareReportRequest.HardwareInfo har
return true; return true;
} }
} }
} catch (SQLException | IOException throwables) } catch (SQLException | IOException throwables) {
{
LogHelper.error(throwables); LogHelper.error(throwables);
throw new SecurityException("SQL error. Please try again later"); throw new SecurityException("SQL error. Please try again later");
} }
return false; return false;
} }
private void changePublicKey(Connection connection, long id, byte[] publicKey) throws SQLException { private void changePublicKey(Connection connection, long id, byte[] publicKey) throws SQLException {
PreparedStatement s = connection.prepareStatement(sqlUpdateHardware); PreparedStatement s = connection.prepareStatement(sqlUpdateHardware);
s.setBlob(1, new ByteArrayInputStream(publicKey)); s.setBlob(1, new ByteArrayInputStream(publicKey));
s.setLong(2, id); s.setLong(2, id);
s.executeUpdate(); s.executeUpdate();
} }
private void writeHwidLog(Connection connection, long hwidId, byte[] newPublicKey) throws SQLException { private void writeHwidLog(Connection connection, long hwidId, byte[] newPublicKey) throws SQLException {
PreparedStatement s = connection.prepareStatement(sqlCreateHWIDLog); PreparedStatement s = connection.prepareStatement(sqlCreateHWIDLog);
s.setLong(1, hwidId); s.setLong(1, hwidId);
s.setBlob(2, new ByteArrayInputStream(newPublicKey)); s.setBlob(2, new ByteArrayInputStream(newPublicKey));
s.executeUpdate(); s.executeUpdate();
} }
private void setUserHardwareId(Connection connection, String username, long hwidId) throws SQLException { private void setUserHardwareId(Connection connection, String username, long hwidId) throws SQLException {
if(sqlUpdateUsers == null || username == null) return; if (sqlUpdateUsers == null || username == null) return;
PreparedStatement s = connection.prepareStatement(sqlUpdateUsers); PreparedStatement s = connection.prepareStatement(sqlUpdateUsers);
s.setLong(1, hwidId); s.setLong(1, hwidId);
s.setString(2, username); s.setString(2, username);

View file

@ -3,8 +3,7 @@
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
public interface JoinServerProtectHandler { public interface JoinServerProtectHandler {
default boolean onJoinServer(String serverID, String username, Client client) default boolean onJoinServer(String serverID, String username, Client client) {
{
return true; return true;
} }
} }

View file

@ -32,8 +32,8 @@ default void verifySecureLevelKey(byte[] publicKey, byte[] data, byte[] signatur
default SecurityReportRequestEvent onSecurityReport(SecurityReportResponse report, Client client) { default SecurityReportRequestEvent onSecurityReport(SecurityReportResponse report, Client client) {
return new SecurityReportRequestEvent(); return new SecurityReportRequestEvent();
} }
default VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client)
{ default VerifySecureLevelKeyRequestEvent onSuccessVerify(Client client) {
return new VerifySecureLevelKeyRequestEvent(); return new VerifySecureLevelKeyRequestEvent();
} }
} }

View file

@ -32,19 +32,18 @@ public Path process(Path inputFile) throws IOException {
Configuration proguard_cfg = new Configuration(); Configuration proguard_cfg = new Configuration();
ConfigurationParser parser = new ConfigurationParser(server.proguardConf.buildConfig(inputFile, outputJar), ConfigurationParser parser = new ConfigurationParser(server.proguardConf.buildConfig(inputFile, outputJar),
server.proguardConf.proguard.toFile(), System.getProperties()); server.proguardConf.proguard.toFile(), System.getProperties());
if (JVMHelper.JVM_VERSION >= 9) if (JVMHelper.JVM_VERSION >= 9) {
{
Path javaJModsPath = Paths.get(System.getProperty("java.home")).resolve("jmods"); Path javaJModsPath = Paths.get(System.getProperty("java.home")).resolve("jmods");
if(!IOHelper.exists(javaJModsPath)) if (!IOHelper.exists(javaJModsPath)) {
{
LogHelper.warning("Directory %s not found. It is not good", javaJModsPath); LogHelper.warning("Directory %s not found. It is not good", javaJModsPath);
} } else {
else
{
//Find javaFX libraries //Find javaFX libraries
if(!IOHelper.exists(javaJModsPath.resolve("javafx.base.jmod"))) LogHelper.error("javafx.base.jmod not found. Launcher can be assembled incorrectly. Maybe you need to install OpenJFX?"); if (!IOHelper.exists(javaJModsPath.resolve("javafx.base.jmod")))
if(!IOHelper.exists(javaJModsPath.resolve("javafx.graphics.jmod"))) LogHelper.error("javafx.graphics.jmod not found. Launcher can be assembled incorrectly. Maybe you need to install OpenJFX?"); LogHelper.error("javafx.base.jmod not found. Launcher can be assembled incorrectly. Maybe you need to install OpenJFX?");
if(!IOHelper.exists(javaJModsPath.resolve("javafx.controls.jmod"))) LogHelper.error("javafx.controls.jmod not found. Launcher can be assembled incorrectly. Maybe you need to install OpenJFX?"); if (!IOHelper.exists(javaJModsPath.resolve("javafx.graphics.jmod")))
LogHelper.error("javafx.graphics.jmod not found. Launcher can be assembled incorrectly. Maybe you need to install OpenJFX?");
if (!IOHelper.exists(javaJModsPath.resolve("javafx.controls.jmod")))
LogHelper.error("javafx.controls.jmod not found. Launcher can be assembled incorrectly. Maybe you need to install OpenJFX?");
} }
} }
try { try {

View file

@ -58,31 +58,26 @@ public void invoke(String... args) throws Exception {
server.certificateManager.writePrivateKey(Paths.get(name.concat(".key")), pair.getPrivate()); server.certificateManager.writePrivateKey(Paths.get(name.concat(".key")), pair.getPrivate());
server.certificateManager.writeCertificate(Paths.get(name.concat(".crt")), cert); server.certificateManager.writeCertificate(Paths.get(name.concat(".crt")), cert);
} }
if(args[0].equals("authstresser")) if (args[0].equals("authstresser")) {
{
AuthProviderPair pair = server.config.getAuthProviderPair(); AuthProviderPair pair = server.config.getAuthProviderPair();
AuthPlainPassword plainPassword = new AuthPlainPassword("test"); AuthPlainPassword plainPassword = new AuthPlainPassword("test");
Runnable runnable = () -> { Runnable runnable = () -> {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
for(int i=0;i<100000;++i) for (int i = 0; i < 100000; ++i) {
{
try { try {
pair.provider.auth("Test", plainPassword, "127.0.0.1"); pair.provider.auth("Test", plainPassword, "127.0.0.1");
} catch (AuthException ignored) } catch (AuthException ignored) {
{
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if((i % 10000) == 0) if ((i % 10000) == 0) {
{
LogHelper.info("Completed %d requests", i); LogHelper.info("Completed %d requests", i);
} }
} }
LogHelper.info("Completed all requests. Time %d ms", System.currentTimeMillis() - startTime); LogHelper.info("Completed all requests. Time %d ms", System.currentTimeMillis() - startTime);
}; };
for(int i=0;i<7;++i) for (int i = 0; i < 7; ++i) {
{
CommonHelper.newThread(String.format("Stresser #%d", i), true, runnable).start(); CommonHelper.newThread(String.format("Stresser #%d", i), true, runnable).start();
} }
} }

View file

@ -63,11 +63,9 @@ public void invoke(String... args) throws IOException, CommandException {
client.setTitle(dirName); client.setTitle(dirName);
client.setDir(dirName); client.setDir(dirName);
client.setUUID(UUID.randomUUID()); client.setUUID(UUID.randomUUID());
if(client.getServers() != null) if (client.getServers() != null) {
{ ClientProfile.ServerProfile serverProfile = client.getDefaultServerProfile();
ClientProfile.ServerProfile serverProfile = client.getDefaultServerProfile(); if (serverProfile != null) {
if(serverProfile != null)
{
serverProfile.name = dirName; serverProfile.name = dirName;
} }
} }

View file

@ -27,8 +27,7 @@ public SaveProfilesCommand(LaunchServer server) {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void saveProfile(ClientProfile profile, Path path) throws IOException { public static void saveProfile(ClientProfile profile, Path path) throws IOException {
if (profile.getUUID() == null) profile.setUUID(UUID.randomUUID()); if (profile.getUUID() == null) profile.setUUID(UUID.randomUUID());
if(profile.getServers().size() == 0) if (profile.getServers().size() == 0) {
{
ClientProfile.ServerProfile serverProfile = new ClientProfile.ServerProfile(); ClientProfile.ServerProfile serverProfile = new ClientProfile.ServerProfile();
serverProfile.isDefault = true; serverProfile.isDefault = true;
serverProfile.name = profile.getTitle(); serverProfile.name = profile.getTitle();
@ -36,19 +35,16 @@ public static void saveProfile(ClientProfile profile, Path path) throws IOExcept
serverProfile.serverPort = profile.getServerPort(); serverProfile.serverPort = profile.getServerPort();
profile.getServers().add(serverProfile); profile.getServers().add(serverProfile);
} }
for(OptionalFile file : profile.getOptional()) for (OptionalFile file : profile.getOptional()) {
{ if (file.list != null) {
if(file.list != null)
{
String[] list = file.list; String[] list = file.list;
file.list = null; file.list = null;
if(file.actions == null) file.actions = new ArrayList<>(2); if (file.actions == null) file.actions = new ArrayList<>(2);
OptionalAction action; OptionalAction action;
switch (file.type) switch (file.type) {
{
case FILE: case FILE:
OptionalActionFile result = new OptionalActionFile(new HashMap<>()); OptionalActionFile result = new OptionalActionFile(new HashMap<>());
for(String s : list) result.files.put(s, ""); for (String s : list) result.files.put(s, "");
action = result; action = result;
break; break;
case CLASSPATH: case CLASSPATH:

View file

@ -25,7 +25,7 @@ public String getUsageDescription() {
public void invoke(String... args) throws IOException { public void invoke(String... args) throws IOException {
server.syncProfilesDir(); server.syncProfilesDir();
LogHelper.subInfo("Profiles successfully resynced"); LogHelper.subInfo("Profiles successfully resynced");
server.syncUpdatesDir(null); server.syncUpdatesDir(null);
LogHelper.subInfo("Updates dir successfully resynced"); LogHelper.subInfo("Updates dir successfully resynced");
} }

View file

@ -29,7 +29,8 @@ public class LauncherModuleLoader {
private final LaunchServer server; private final LaunchServer server;
public LauncherModuleLoader(LaunchServer server) { public LauncherModuleLoader(LaunchServer server) {
this.server = server; modulesDir = server.dir.resolve("launcher-modules"); this.server = server;
modulesDir = server.dir.resolve("launcher-modules");
} }
public void init() { public void init() {
@ -140,19 +141,17 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
return super.visitFile(file, attrs); return super.visitFile(file, attrs);
} }
} }
public void addClassFieldsToProperties(Map<String, Object> propertyMap, String prefix, Object object, Class<?> classOfObject) throws IllegalAccessException { public void addClassFieldsToProperties(Map<String, Object> propertyMap, String prefix, Object object, Class<?> classOfObject) throws IllegalAccessException {
Field[] fields = classOfObject.getFields(); Field[] fields = classOfObject.getFields();
for (Field field : fields) { for (Field field : fields) {
if ((field.getModifiers() & Modifier.STATIC) != 0) continue; if ((field.getModifiers() & Modifier.STATIC) != 0) continue;
Object obj = field.get(object); Object obj = field.get(object);
String propertyName = prefix.concat(".").concat(field.getName().toLowerCase(Locale.US)); String propertyName = prefix.concat(".").concat(field.getName().toLowerCase(Locale.US));
if(InjectClassAcceptor.isSerializableValue(obj)) if (InjectClassAcceptor.isSerializableValue(obj)) {
{
LogHelper.dev("Property name %s", propertyName); LogHelper.dev("Property name %s", propertyName);
propertyMap.put(propertyName, obj); propertyMap.put(propertyName, obj);
} } else {
else
{
//Try recursive add fields //Try recursive add fields
addClassFieldsToProperties(propertyMap, propertyName, obj, obj.getClass()); addClassFieldsToProperties(propertyMap, propertyName, obj, obj.getClass());
} }

View file

@ -8,10 +8,9 @@
import java.util.Map; import java.util.Map;
public class PingServerManager { public class PingServerManager {
public static final long REPORT_EXPIRED_TIME = 20*1000; public static final long REPORT_EXPIRED_TIME = 20 * 1000;
public static class ServerInfoEntry public static class ServerInfoEntry {
{
public PingServerReportRequest.PingServerReport lastReport; public PingServerReportRequest.PingServerReport lastReport;
public long lastReportTime; public long lastReportTime;
public final ClientProfile profile; public final ClientProfile profile;
@ -26,37 +25,34 @@ public ServerInfoEntry(ClientProfile profile) {
this.profile = profile; this.profile = profile;
} }
public boolean isExpired() public boolean isExpired() {
{
return System.currentTimeMillis() - lastReportTime > REPORT_EXPIRED_TIME; return System.currentTimeMillis() - lastReportTime > REPORT_EXPIRED_TIME;
} }
} }
public final Map<String, ServerInfoEntry> map = new HashMap<>(); public final Map<String, ServerInfoEntry> map = new HashMap<>();
private final LaunchServer server; private final LaunchServer server;
public PingServerManager(LaunchServer server) { public PingServerManager(LaunchServer server) {
this.server = server; this.server = server;
} }
public void syncServers()
{ public void syncServers() {
server.getProfiles().forEach((p) -> { server.getProfiles().forEach((p) -> {
for(ClientProfile.ServerProfile sp : p.getServers()) for (ClientProfile.ServerProfile sp : p.getServers()) {
{
ServerInfoEntry entry = map.get(sp.name); ServerInfoEntry entry = map.get(sp.name);
if(entry == null) if (entry == null) {
{
map.put(sp.name, new ServerInfoEntry(p)); map.put(sp.name, new ServerInfoEntry(p));
} }
} }
}); });
} }
public boolean updateServer(String name, PingServerReportRequest.PingServerReport report)
{ public boolean updateServer(String name, PingServerReportRequest.PingServerReport report) {
ServerInfoEntry entry = map.get(name); ServerInfoEntry entry = map.get(name);
if(entry == null) if (entry == null)
return false; return false;
else else {
{
entry.lastReportTime = System.currentTimeMillis(); entry.lastReportTime = System.currentTimeMillis();
entry.lastReport = report; entry.lastReport = report;
return true; return true;

View file

@ -62,16 +62,15 @@ public static class TrustLevel {
public byte[] publicKey; public byte[] publicKey;
public HardwareReportRequest.HardwareInfo hardwareInfo; public HardwareReportRequest.HardwareInfo hardwareInfo;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public<T> T getProperty(String name) public <T> T getProperty(String name) {
{ if (properties == null) properties = new HashMap<>();
if(properties == null) properties = new HashMap<>();
return (T) properties.get(name); return (T) properties.get(name);
} }
public<T> void setProperty(String name, T object) public <T> void setProperty(String name, T object) {
{ if (properties == null) properties = new HashMap<>();
if(properties == null) properties = new HashMap<>();
properties.put(name, object); properties.put(name, object);
} }
} }

View file

@ -61,7 +61,7 @@ public void initChannel(SocketChannel ch) {
pipeline.addLast("forward-http", new NettyIpForwardHandler(context)); pipeline.addLast("forward-http", new NettyIpForwardHandler(context));
pipeline.addLast("websock-comp", new WebSocketServerCompressionHandler()); pipeline.addLast("websock-comp", new WebSocketServerCompressionHandler());
pipeline.addLast("websock-codec", new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true)); pipeline.addLast("websock-codec", new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
if(!server.config.netty.disableWebApiInterface) if (!server.config.netty.disableWebApiInterface)
pipeline.addLast("webapi", new NettyWebAPIHandler(context)); pipeline.addLast("webapi", new NettyWebAPIHandler(context));
if (server.config.netty.fileServerEnabled) if (server.config.netty.fileServerEnabled)
pipeline.addLast("fileserver", new FileServerHandler(server.updatesDir, true, config.showHiddenFiles)); pipeline.addLast("fileserver", new FileServerHandler(server.updatesDir, true, config.showHiddenFiles));

View file

@ -67,8 +67,7 @@ public WebSocketService(ChannelGroup channels, LaunchServer server) {
this.gson = Launcher.gsonManager.gson; this.gson = Launcher.gsonManager.gson;
} }
public void forEachActiveChannels(BiConsumer<Channel, WebSocketFrameHandler> callback) public void forEachActiveChannels(BiConsumer<Channel, WebSocketFrameHandler> callback) {
{
channels.forEach((channel) -> { channels.forEach((channel) -> {
if (channel == null || channel.pipeline() == null) return; if (channel == null || channel.pipeline() == null) return;
WebSocketFrameHandler wsHandler = channel.pipeline().get(WebSocketFrameHandler.class); WebSocketFrameHandler wsHandler = channel.pipeline().get(WebSocketFrameHandler.class);
@ -113,32 +112,28 @@ public void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client
} }
process(ctx, response, client, ip); process(ctx, response, client, ip);
long executeTime = System.nanoTime() - startTimeNanos; long executeTime = System.nanoTime() - startTimeNanos;
if(executeTime > 0) if (executeTime > 0) {
{
addRequestTimeToStats(executeTime); addRequestTimeToStats(executeTime);
} }
} }
public void addRequestTimeToStats(long nanos) public void addRequestTimeToStats(long nanos) {
{ if (nanos < 100_000_000L) // < 100 millis
if(nanos < 100_000_000L) // < 100 millis
{ {
shortRequestCounter.getAndIncrement(); shortRequestCounter.getAndIncrement();
shortRequestLatency.getAndAdd(nanos); shortRequestLatency.getAndAdd(nanos);
} } else if (nanos < 1_000_000_000L) // > 100 millis and < 1 second
else if(nanos < 1_000_000_000L) // > 100 millis and < 1 second
{ {
middleRequestCounter.getAndIncrement(); middleRequestCounter.getAndIncrement();
middleRequestLatency.getAndAdd(nanos); middleRequestLatency.getAndAdd(nanos);
} } else // > 1 second
else // > 1 second
{ {
longRequestCounter.getAndIncrement(); longRequestCounter.getAndIncrement();
longRequestLatency.getAndAdd(nanos); longRequestLatency.getAndAdd(nanos);
} }
long lastTime = lastRequestTime.get(); long lastTime = lastRequestTime.get();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if(currentTime - lastTime > 60*1000) //1 minute if (currentTime - lastTime > 60 * 1000) //1 minute
{ {
lastRequestTime.set(currentTime); lastRequestTime.set(currentTime);
shortRequestLatency.set(0); shortRequestLatency.set(0);

View file

@ -2,10 +2,11 @@
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.FullHttpRequest;
import pro.gravit.launchserver.socket.NettyConnectContext; import pro.gravit.launchserver.socket.NettyConnectContext;
import java.util.*; import java.util.Comparator;
import java.util.TreeSet;
public class NettyWebAPIHandler extends SimpleChannelInboundHandler<FullHttpRequest> { public class NettyWebAPIHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
private final NettyConnectContext context; private final NettyConnectContext context;
@ -14,10 +15,12 @@ public NettyWebAPIHandler(NettyConnectContext context) {
super(); super();
this.context = context; this.context = context;
} }
@FunctionalInterface @FunctionalInterface
public interface SimpleSeverletHandler { public interface SimpleSeverletHandler {
void handle(ChannelHandlerContext ctx, FullHttpRequest msg, NettyConnectContext context) throws Exception; void handle(ChannelHandlerContext ctx, FullHttpRequest msg, NettyConnectContext context) throws Exception;
} }
public static class SeverletPathPair { public static class SeverletPathPair {
public final String key; public final String key;
public final SimpleSeverletHandler callback; public final SimpleSeverletHandler callback;
@ -27,37 +30,36 @@ public SeverletPathPair(String key, SimpleSeverletHandler callback) {
this.callback = callback; this.callback = callback;
} }
} }
private static final TreeSet<SeverletPathPair> severletList = new TreeSet<>(Comparator.comparingInt((e) -> -e.key.length())); private static final TreeSet<SeverletPathPair> severletList = new TreeSet<>(Comparator.comparingInt((e) -> -e.key.length()));
public static SeverletPathPair addNewSeverlet(String path, SimpleSeverletHandler callback)
{ public static SeverletPathPair addNewSeverlet(String path, SimpleSeverletHandler callback) {
SeverletPathPair pair = new SeverletPathPair("/webapi/".concat(path), callback); SeverletPathPair pair = new SeverletPathPair("/webapi/".concat(path), callback);
severletList.add(pair); severletList.add(pair);
return pair; return pair;
} }
public static SeverletPathPair addUnsafeSeverlet(String path, SimpleSeverletHandler callback)
{ public static SeverletPathPair addUnsafeSeverlet(String path, SimpleSeverletHandler callback) {
SeverletPathPair pair = new SeverletPathPair(path, callback); SeverletPathPair pair = new SeverletPathPair(path, callback);
severletList.add(pair); severletList.add(pair);
return pair; return pair;
} }
public static void removeSeverlet(SeverletPathPair pair)
{ public static void removeSeverlet(SeverletPathPair pair) {
severletList.remove(pair); severletList.remove(pair);
} }
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
boolean isNext = true; boolean isNext = true;
for(SeverletPathPair pair : severletList) for (SeverletPathPair pair : severletList) {
{ if (msg.uri().startsWith(pair.key)) {
if(msg.uri().startsWith(pair.key))
{
pair.callback.handle(ctx, msg, context); pair.callback.handle(ctx, msg, context);
isNext = false; isNext = false;
break; break;
} }
} }
if(isNext) if (isNext) {
{
msg.retain(); msg.retain();
ctx.fireChannelRead(msg); ctx.fireChannelRead(msg);
} }

View file

@ -50,13 +50,13 @@ public void channelActive(ChannelHandlerContext ctx) {
client = new Client(null); client = new Client(null);
Channel ch = ctx.channel(); Channel ch = ctx.channel();
service.registerClient(ch); service.registerClient(ch);
ctx.executor().scheduleAtFixedRate(() -> ch.writeAndFlush(new PingWebSocketFrame(), ch.voidPromise()), 30L , 30L, TimeUnit.SECONDS); ctx.executor().scheduleAtFixedRate(() -> ch.writeAndFlush(new PingWebSocketFrame(), ch.voidPromise()), 30L, 30L, TimeUnit.SECONDS);
} }
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) { protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
// ping and pong frames already handled // ping and pong frames already handled
if(hooks.hook(ctx, frame)) return; if (hooks.hook(ctx, frame)) return;
if (frame instanceof TextWebSocketFrame) { if (frame instanceof TextWebSocketFrame) {
service.process(ctx, (TextWebSocketFrame) frame, client, context.ip); service.process(ctx, (TextWebSocketFrame) frame, client, context.ip);
} else if ((frame instanceof PingWebSocketFrame)) { } else if ((frame instanceof PingWebSocketFrame)) {

View file

@ -85,8 +85,7 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti
clientData.username = aresult.username; clientData.username = aresult.username;
else else
clientData.username = login; clientData.username = login;
if(aresult instanceof AuthProviderDAOResult) if (aresult instanceof AuthProviderDAOResult) {
{
clientData.daoObject = ((AuthProviderDAOResult) aresult).daoObject; clientData.daoObject = ((AuthProviderDAOResult) aresult).daoObject;
} }
result.accessToken = aresult.accessToken; result.accessToken = aresult.accessToken;
@ -104,9 +103,7 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti
if (LogHelper.isDebugEnabled()) { if (LogHelper.isDebugEnabled()) {
LogHelper.debug("Auth: %s accessToken %s uuid: %s", login, result.accessToken, uuid.toString()); LogHelper.debug("Auth: %s accessToken %s uuid: %s", login, result.accessToken, uuid.toString());
} }
} } else {
else
{
uuid = pair.handler.usernameToUUID(aresult.username); uuid = pair.handler.usernameToUUID(aresult.username);
result.accessToken = null; result.accessToken = null;
} }

View file

@ -20,13 +20,11 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
sendResult(new CurrentUserRequestEvent(collectUserInfoFromClient(client))); sendResult(new CurrentUserRequestEvent(collectUserInfoFromClient(client)));
} }
public static CurrentUserRequestEvent.UserInfo collectUserInfoFromClient(Client client) throws IOException public static CurrentUserRequestEvent.UserInfo collectUserInfoFromClient(Client client) throws IOException {
{
CurrentUserRequestEvent.UserInfo result = new CurrentUserRequestEvent.UserInfo(); CurrentUserRequestEvent.UserInfo result = new CurrentUserRequestEvent.UserInfo();
if(client.auth != null && client.isAuth && client.username != null) { if (client.auth != null && client.isAuth && client.username != null) {
UUID uuid = client.auth.handler.usernameToUUID(client.username); UUID uuid = client.auth.handler.usernameToUUID(client.username);
if(uuid != null) if (uuid != null) {
{
result.playerProfile = ProfileByUUIDResponse.getProfile(uuid, client.username, client.profile == null ? null : client.profile.getTitle(), client.auth.textureProvider); result.playerProfile = ProfileByUUIDResponse.getProfile(uuid, client.username, client.profile == null ? null : client.profile.getTitle(), client.auth.textureProvider);
} }
} }

View file

@ -54,16 +54,15 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
} else { } else {
service.forEachActiveChannels(((channel, webSocketFrameHandler) -> { service.forEachActiveChannels(((channel, webSocketFrameHandler) -> {
Client client1 = webSocketFrameHandler.getClient(); Client client1 = webSocketFrameHandler.getClient();
if(client1 != null && client.isAuth && client.username != null && client1.username.equals(username)) if (client1 != null && client.isAuth && client.username != null && client1.username.equals(username)) {
{
exit(server, webSocketFrameHandler, channel, ExitRequestEvent.ExitReason.SERVER); exit(server, webSocketFrameHandler, channel, ExitRequestEvent.ExitReason.SERVER);
} }
})); }));
sendResult(new ExitRequestEvent(ExitRequestEvent.ExitReason.NO_EXIT)); sendResult(new ExitRequestEvent(ExitRequestEvent.ExitReason.NO_EXIT));
} }
} }
public static void exit(LaunchServer server, WebSocketFrameHandler wsHandler, Channel channel, ExitRequestEvent.ExitReason reason)
{ public static void exit(LaunchServer server, WebSocketFrameHandler wsHandler, Channel channel, ExitRequestEvent.ExitReason reason) {
Client chClient = wsHandler.getClient(); Client chClient = wsHandler.getClient();
Client newCusClient = new Client(null); Client newCusClient = new Client(null);

View file

@ -28,11 +28,9 @@ public void execute(ChannelHandlerContext ctx, Client client) {
boolean success; boolean success;
try { try {
server.authHookManager.joinServerHook.hook(this, client); server.authHookManager.joinServerHook.hook(this, client);
if(server.config.protectHandler instanceof JoinServerProtectHandler) if (server.config.protectHandler instanceof JoinServerProtectHandler) {
{
success = ((JoinServerProtectHandler) server.config.protectHandler).onJoinServer(serverID, username, client); success = ((JoinServerProtectHandler) server.config.protectHandler).onJoinServer(serverID, username, client);
if(!success) if (!success) {
{
sendResult(new JoinServerRequestEvent(false)); sendResult(new JoinServerRequestEvent(false));
return; return;
} }

View file

@ -28,12 +28,9 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
} }
WebSocketFrameHandler frameHandler = ctx.pipeline().get(WebSocketFrameHandler.class); WebSocketFrameHandler frameHandler = ctx.pipeline().get(WebSocketFrameHandler.class);
frameHandler.setClient(rClient); frameHandler.setClient(rClient);
if(needUserInfo) if (needUserInfo) {
{
sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(rClient))); sendResult(new RestoreSessionRequestEvent(CurrentUserResponse.collectUserInfoFromClient(rClient)));
} } else {
else
{
sendResult(new RestoreSessionRequestEvent()); sendResult(new RestoreSessionRequestEvent());
} }
} }

View file

@ -10,6 +10,7 @@
public class PingServerReportResponse extends SimpleResponse { public class PingServerReportResponse extends SimpleResponse {
public PingServerReportRequest.PingServerReport data; public PingServerReportRequest.PingServerReport data;
public String name; public String name;
@Override @Override
public String getType() { public String getType() {
return "pingServerReport"; return "pingServerReport";
@ -17,8 +18,7 @@ public String getType() {
@Override @Override
public void execute(ChannelHandlerContext ctx, Client client) throws Exception { public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
if(!client.isAuth || client.permissions == null || !client.permissions.isPermission(ClientPermissions.PermissionConsts.MANAGEMENT)) if (!client.isAuth || client.permissions == null || !client.permissions.isPermission(ClientPermissions.PermissionConsts.MANAGEMENT)) {
{
sendError("Access denied"); sendError("Access denied");
return; return;
} }

View file

@ -13,6 +13,7 @@
public class PingServerResponse extends SimpleResponse { public class PingServerResponse extends SimpleResponse {
public List<String> serverNames; //May be null public List<String> serverNames; //May be null
@Override @Override
public String getType() { public String getType() {
return "pingServer"; return "pingServer";
@ -21,24 +22,18 @@ public String getType() {
@Override @Override
public void execute(ChannelHandlerContext ctx, Client client) throws Exception { public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
Map<String, PingServerReportRequest.PingServerReport> map = new HashMap<>(); Map<String, PingServerReportRequest.PingServerReport> map = new HashMap<>();
if(serverNames == null) if (serverNames == null) {
{
server.pingServerManager.map.forEach((name, entity) -> { server.pingServerManager.map.forEach((name, entity) -> {
if(server.config.protectHandler instanceof ProfilesProtectHandler) if (server.config.protectHandler instanceof ProfilesProtectHandler) {
{ if (!((ProfilesProtectHandler) server.config.protectHandler).canGetProfile(entity.profile, client)) {
if(!((ProfilesProtectHandler) server.config.protectHandler).canGetProfile(entity.profile, client))
{
return; return;
} }
} }
if(!entity.isExpired()) if (!entity.isExpired()) {
{
map.put(name, entity.lastReport); map.put(name, entity.lastReport);
} }
}); });
} } else {
else
{
sendError("Not implemented"); sendError("Not implemented");
return; return;
} }

View file

@ -17,11 +17,11 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
ServerStatusRequestEvent event = new ServerStatusRequestEvent(server.config.projectName); ServerStatusRequestEvent event = new ServerStatusRequestEvent(server.config.projectName);
event.totalJavaMemory = JVMHelper.RUNTIME.totalMemory(); event.totalJavaMemory = JVMHelper.RUNTIME.totalMemory();
event.freeJavaMemory = JVMHelper.RUNTIME.freeMemory(); event.freeJavaMemory = JVMHelper.RUNTIME.freeMemory();
event.shortLatency = ( service.shortRequestLatency.get() / service.shortRequestCounter.get() ) / 1_000_000; event.shortLatency = (service.shortRequestLatency.get() / service.shortRequestCounter.get()) / 1_000_000;
event.middleLatency = ( service.middleRequestLatency.get() / service.middleRequestCounter.get() ) / 1_000_000; event.middleLatency = (service.middleRequestLatency.get() / service.middleRequestCounter.get()) / 1_000_000;
event.longLatency = ( service.longRequestLatency.get() / service.longRequestCounter.get() ) / 1_000_000; event.longLatency = (service.longRequestLatency.get() / service.longRequestCounter.get()) / 1_000_000;
event.latency = ( ( service.shortRequestLatency.get() + service.middleRequestLatency.get() + service.longRequestLatency.get() ) / event.latency = ((service.shortRequestLatency.get() + service.middleRequestLatency.get() + service.longRequestLatency.get()) /
( service.shortRequestCounter.get() + service.middleRequestCounter.get() + service.longRequestCounter.get() ) ) / 1_000_000; (service.shortRequestCounter.get() + service.middleRequestCounter.get() + service.longRequestCounter.get())) / 1_000_000;
sendResult(event); sendResult(event);
} }
} }

View file

@ -2,9 +2,9 @@
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent; import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent;
import pro.gravit.launchserver.auth.AuthProviderPair;
import pro.gravit.launchserver.socket.Client; import pro.gravit.launchserver.socket.Client;
import pro.gravit.launchserver.socket.response.SimpleResponse; import pro.gravit.launchserver.socket.response.SimpleResponse;
import pro.gravit.launchserver.auth.AuthProviderPair;
import java.util.UUID; import java.util.UUID;
@ -21,10 +21,9 @@ public String getType() {
public void execute(ChannelHandlerContext ctx, Client client) throws Exception { public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
UUID uuid; UUID uuid;
AuthProviderPair pair = client.auth; AuthProviderPair pair = client.auth;
if(pair == null) pair = server.config.getAuthProviderPair(); if (pair == null) pair = server.config.getAuthProviderPair();
uuid = pair.handler.usernameToUUID(username); uuid = pair.handler.usernameToUUID(username);
if(uuid == null) if (uuid == null) {
{
sendError("User not found"); sendError("User not found");
return; return;
} }

View file

@ -17,17 +17,13 @@ public String getType() {
@Override @Override
public void execute(ChannelHandlerContext ctx, Client client) throws Exception { public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
if(server.config.protectHandler instanceof HardwareProtectHandler) if (server.config.protectHandler instanceof HardwareProtectHandler) {
{
try { try {
((HardwareProtectHandler) server.config.protectHandler).onHardwareReport(this, client); ((HardwareProtectHandler) server.config.protectHandler).onHardwareReport(this, client);
} catch (SecurityException e) } catch (SecurityException e) {
{
sendError(e.getMessage()); sendError(e.getMessage());
} }
} } else {
else
{
sendResult(new HardwareReportRequestEvent()); sendResult(new HardwareReportRequestEvent());
} }
} }

View file

@ -40,8 +40,7 @@ public void execute(ChannelHandlerContext ctx, Client client) throws Exception {
client.trustLevel.publicKey = publicKey; client.trustLevel.publicKey = publicKey;
try { try {
sendResult(secureProtectHandler.onSuccessVerify(client)); sendResult(secureProtectHandler.onSuccessVerify(client));
} catch (SecurityException e) } catch (SecurityException e) {
{
sendError(e.getMessage()); sendError(e.getMessage());
} }

View file

@ -22,8 +22,8 @@ public class ClientLauncherWrapper {
public static final String NO_JAVA_CHECK_PROPERTY = "launcher.noJavaCheck"; public static final String NO_JAVA_CHECK_PROPERTY = "launcher.noJavaCheck";
public static boolean noJavaCheck = Boolean.getBoolean(NO_JAVA_CHECK_PROPERTY); public static boolean noJavaCheck = Boolean.getBoolean(NO_JAVA_CHECK_PROPERTY);
public static boolean waitProcess = Boolean.getBoolean(WAIT_PROCESS_PROPERTY); public static boolean waitProcess = Boolean.getBoolean(WAIT_PROCESS_PROPERTY);
public static class JavaVersion
{ public static class JavaVersion {
public final Path jvmDir; public final Path jvmDir;
public final int version; public final int version;
public boolean enabledJavaFX; public boolean enabledJavaFX;
@ -33,31 +33,29 @@ public JavaVersion(Path jvmDir, int version) {
this.version = version; this.version = version;
this.enabledJavaFX = true; this.enabledJavaFX = true;
} }
public static JavaVersion getCurrentJavaVersion()
{ public static JavaVersion getCurrentJavaVersion() {
return new JavaVersion(Paths.get(System.getProperty("java.home")), JVMHelper.getVersion()); return new JavaVersion(Paths.get(System.getProperty("java.home")), JVMHelper.getVersion());
} }
public static JavaVersion getByPath(Path jvmDir) throws IOException { public static JavaVersion getByPath(Path jvmDir) throws IOException {
Path releaseFile = jvmDir.resolve("release"); Path releaseFile = jvmDir.resolve("release");
if(!IOHelper.isFile(releaseFile)) return null; if (!IOHelper.isFile(releaseFile)) return null;
Properties properties = new Properties(); Properties properties = new Properties();
properties.load(IOHelper.newReader(releaseFile)); properties.load(IOHelper.newReader(releaseFile));
int javaVersion = getJavaVersion(properties.getProperty("JAVA_VERSION").replaceAll("\"", "")); int javaVersion = getJavaVersion(properties.getProperty("JAVA_VERSION").replaceAll("\"", ""));
JavaVersion resultJavaVersion = new JavaVersion(jvmDir, javaVersion); JavaVersion resultJavaVersion = new JavaVersion(jvmDir, javaVersion);
if(javaVersion <= 8) if (javaVersion <= 8) {
{
resultJavaVersion.enabledJavaFX = isExistExtJavaLibrary(jvmDir, "jfxrt"); resultJavaVersion.enabledJavaFX = isExistExtJavaLibrary(jvmDir, "jfxrt");
} } else {
else
{
resultJavaVersion.enabledJavaFX = tryFindModule(jvmDir, "javafx.base") != null; resultJavaVersion.enabledJavaFX = tryFindModule(jvmDir, "javafx.base") != null;
if(!resultJavaVersion.enabledJavaFX) if (!resultJavaVersion.enabledJavaFX)
resultJavaVersion.enabledJavaFX = tryFindModule(jvmDir.resolve("jre"), "javafx.base") != null; resultJavaVersion.enabledJavaFX = tryFindModule(jvmDir.resolve("jre"), "javafx.base") != null;
} }
return resultJavaVersion; return resultJavaVersion;
} }
public static boolean isExistExtJavaLibrary(Path jvmDir, String name)
{ public static boolean isExistExtJavaLibrary(Path jvmDir, String name) {
Path jrePath = jvmDir.resolve("lib").resolve("ext").resolve(name.concat(".jar")); Path jrePath = jvmDir.resolve("lib").resolve("ext").resolve(name.concat(".jar"));
Path jdkPath = jvmDir.resolve("jre").resolve("lib").resolve("ext").resolve(name.concat(".jar")); Path jdkPath = jvmDir.resolve("jre").resolve("lib").resolve("ext").resolve(name.concat(".jar"));
return IOHelper.isFile(jrePath) || IOHelper.isFile(jdkPath); return IOHelper.isFile(jrePath) || IOHelper.isFile(jdkPath);
@ -94,12 +92,11 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep
JavaVersion javaVersion = null; JavaVersion javaVersion = null;
try { try {
if(!noJavaCheck) javaVersion = findJava(); if (!noJavaCheck) javaVersion = findJava();
} catch (Throwable e) { } catch (Throwable e) {
LogHelper.error(e); LogHelper.error(e);
} }
if (javaVersion == null) if (javaVersion == null) {
{
javaVersion = JavaVersion.getCurrentJavaVersion(); javaVersion = JavaVersion.getCurrentJavaVersion();
} }
@ -187,64 +184,54 @@ public static boolean tryAddModule(Path[] paths, String moduleName, StringBuilde
return false; return false;
} }
public static JavaVersion findJavaByProgramFiles(Path path) public static JavaVersion findJavaByProgramFiles(Path path) {
{
LogHelper.debug("Check Java in %s", path.toString()); LogHelper.debug("Check Java in %s", path.toString());
JavaVersion selectedJava = null; JavaVersion selectedJava = null;
File[] candidates = path.toFile().listFiles(File::isDirectory); File[] candidates = path.toFile().listFiles(File::isDirectory);
if(candidates == null) return null; if (candidates == null) return null;
for(File candidate : candidates) for (File candidate : candidates) {
{
Path javaPath = candidate.toPath(); Path javaPath = candidate.toPath();
try { try {
JavaVersion javaVersion = JavaVersion.getByPath(javaPath); JavaVersion javaVersion = JavaVersion.getByPath(javaPath);
if(javaVersion == null || javaVersion.version < 8) continue; if (javaVersion == null || javaVersion.version < 8) continue;
LogHelper.debug("Found Java %d in %s (javafx %s)", javaVersion.version, javaVersion.jvmDir.toString(), javaVersion.enabledJavaFX ? "true" : "false"); LogHelper.debug("Found Java %d in %s (javafx %s)", javaVersion.version, javaVersion.jvmDir.toString(), javaVersion.enabledJavaFX ? "true" : "false");
if(javaVersion.enabledJavaFX && (selectedJava == null || !selectedJava.enabledJavaFX)) if (javaVersion.enabledJavaFX && (selectedJava == null || !selectedJava.enabledJavaFX)) {
{
selectedJava = javaVersion; selectedJava = javaVersion;
continue; continue;
} }
if(selectedJava != null && javaVersion.enabledJavaFX && javaVersion.version < selectedJava.version) if (selectedJava != null && javaVersion.enabledJavaFX && javaVersion.version < selectedJava.version) {
{
selectedJava = javaVersion; selectedJava = javaVersion;
} }
} catch (IOException e) { } catch (IOException e) {
LogHelper.error(e); LogHelper.error(e);
} }
} }
if(selectedJava != null) if (selectedJava != null) {
{
LogHelper.debug("Selected Java %d in %s (javafx %s)", selectedJava.version, selectedJava.jvmDir.toString(), selectedJava.enabledJavaFX ? "true" : "false"); LogHelper.debug("Selected Java %d in %s (javafx %s)", selectedJava.version, selectedJava.jvmDir.toString(), selectedJava.enabledJavaFX ? "true" : "false");
} }
return selectedJava; return selectedJava;
} }
public static JavaVersion findJava() public static JavaVersion findJava() {
{ if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) {
if(JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE)
{
JavaVersion result = null; JavaVersion result = null;
Path defaultJvmContainerDir = Paths.get(System.getProperty("java.home")).getParent(); Path defaultJvmContainerDir = Paths.get(System.getProperty("java.home")).getParent();
if(defaultJvmContainerDir.getParent().getFileName().toString().contains("x86")) //Program Files (x86) ? if (defaultJvmContainerDir.getParent().getFileName().toString().contains("x86")) //Program Files (x86) ?
{ {
Path programFiles64 = defaultJvmContainerDir.getParent().getParent().resolve("Program Files").resolve("Java"); Path programFiles64 = defaultJvmContainerDir.getParent().getParent().resolve("Program Files").resolve("Java");
if(IOHelper.isDir(programFiles64)) if (IOHelper.isDir(programFiles64)) {
{
result = findJavaByProgramFiles(programFiles64); result = findJavaByProgramFiles(programFiles64);
} }
} }
if(result == null) if (result == null) {
{
result = findJavaByProgramFiles(defaultJvmContainerDir); result = findJavaByProgramFiles(defaultJvmContainerDir);
} }
return result; return result;
} }
return null; return null;
} }
public static int getJavaVersion(String version) public static int getJavaVersion(String version) {
{
if (version.startsWith("1.")) { if (version.startsWith("1.")) {
version = version.substring(2, 3); version = version.substring(2, 3);
} else { } else {

View file

@ -54,7 +54,7 @@ private static ClientLauncherProcess.ClientParams readParams(SocketAddress addre
params.clientHDir = new HashedDir(input); params.clientHDir = new HashedDir(input);
params.assetHDir = new HashedDir(input); params.assetHDir = new HashedDir(input);
boolean isNeedReadJavaDir = input.readBoolean(); boolean isNeedReadJavaDir = input.readBoolean();
if(isNeedReadJavaDir) if (isNeedReadJavaDir)
params.javaHDir = new HashedDir(input); params.javaHDir = new HashedDir(input);
return params; return params;
} }
@ -98,9 +98,9 @@ public static void main(String[] args) throws Throwable {
List<URL> classpath = new LinkedList<>(); List<URL> classpath = new LinkedList<>();
resolveClassPathStream(clientDir, params.profile.getClassPath()).map(IOHelper::toURL).collect(Collectors.toCollection(() -> classpath)); resolveClassPathStream(clientDir, params.profile.getClassPath()).map(IOHelper::toURL).collect(Collectors.toCollection(() -> classpath));
for(OptionalAction a : params.actions) { for (OptionalAction a : params.actions) {
if(a instanceof OptionalActionClassPath) if (a instanceof OptionalActionClassPath)
resolveClassPathStream(clientDir, ((OptionalActionClassPath) a).args).map(IOHelper::toURL).collect(Collectors.toCollection(() -> classpath)); resolveClassPathStream(clientDir, ((OptionalActionClassPath) a).args).map(IOHelper::toURL).collect(Collectors.toCollection(() -> classpath));
} }
classLoader = new ClientClassLoader(classpath.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); classLoader = new ClientClassLoader(classpath.toArray(new URL[0]), ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(classLoader); Thread.currentThread().setContextClassLoader(classLoader);
@ -152,14 +152,14 @@ public static void main(String[] args) throws Throwable {
// Start WatchService, and only then client // Start WatchService, and only then client
CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start(); CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start();
CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start(); CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
if(javaWatcher != null) if (javaWatcher != null)
CommonHelper.newThread("Java Directory Watcher", true, clientWatcher).start(); CommonHelper.newThread("Java Directory Watcher", true, clientWatcher).start();
verifyHDir(assetDir, params.assetHDir, assetMatcher, digest); verifyHDir(assetDir, params.assetHDir, assetMatcher, digest);
verifyHDir(clientDir, params.clientHDir, clientMatcher, digest); verifyHDir(clientDir, params.clientHDir, clientMatcher, digest);
if(javaWatcher != null) if (javaWatcher != null)
verifyHDir(javaDir, params.javaHDir, null, digest); verifyHDir(javaDir, params.javaHDir, null, digest);
if(params.javaHDir != null) if (params.javaHDir != null)
LauncherEngine.modulesManager.invokeEvent(new ClientProcessLaunchEvent(engine, params)); LauncherEngine.modulesManager.invokeEvent(new ClientProcessLaunchEvent(engine, params));
launch(profile, params); launch(profile, params);
} }
} }

View file

@ -78,8 +78,7 @@ public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir, Path r
this.params.assetHDir = assetHDir; this.params.assetHDir = assetHDir;
this.params.clientHDir = clientHDir; this.params.clientHDir = clientHDir;
this.params.javaHDir = jvmHDir; this.params.javaHDir = jvmHDir;
if(view != null) if (view != null) {
{
this.params.actions = view.getEnabledActions(); this.params.actions = view.getEnabledActions();
} }
this.bits = JVMHelper.JVM_BITS; this.bits = JVMHelper.JVM_BITS;
@ -96,10 +95,8 @@ public static String getPathSeparator() {
private void applyClientProfile() { private void applyClientProfile() {
this.systemClassPath.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString()); this.systemClassPath.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString());
Collections.addAll(this.jvmArgs, this.params.profile.getJvmArgs()); Collections.addAll(this.jvmArgs, this.params.profile.getJvmArgs());
for(OptionalAction a : this.params.actions) for (OptionalAction a : this.params.actions) {
{ if (a instanceof OptionalActionJvmArgs) {
if(a instanceof OptionalActionJvmArgs)
{
this.jvmArgs.addAll(((OptionalActionJvmArgs) a).args); this.jvmArgs.addAll(((OptionalActionJvmArgs) a).args);
} }
} }
@ -164,10 +161,9 @@ public void runWriteParams(SocketAddress address) throws IOException {
output.writeByteArray(serializedMainParams, 0); output.writeByteArray(serializedMainParams, 0);
params.clientHDir.write(output); params.clientHDir.write(output);
params.assetHDir.write(output); params.assetHDir.write(output);
if(params.javaHDir == null || params.javaHDir == params.assetHDir) { //TODO: OLD RUNTIME USE params.assetHDir AS NULL IN java.javaHDir if (params.javaHDir == null || params.javaHDir == params.assetHDir) { //TODO: OLD RUNTIME USE params.assetHDir AS NULL IN java.javaHDir
output.writeBoolean(false); output.writeBoolean(false);
} } else {
else {
output.writeBoolean(true); output.writeBoolean(true);
params.javaHDir.write(output); params.javaHDir.write(output);
} }
@ -279,10 +275,8 @@ private void addModernClientArgs(Collection<String> args) {
Collections.addAll(args, "--server", profile.getServerAddress()); Collections.addAll(args, "--server", profile.getServerAddress());
Collections.addAll(args, "--port", Integer.toString(profile.getServerPort())); Collections.addAll(args, "--port", Integer.toString(profile.getServerPort()));
} }
for(OptionalAction a : actions) for (OptionalAction a : actions) {
{ if (a instanceof OptionalActionClientArgs) {
if(a instanceof OptionalActionClientArgs)
{
args.addAll(((OptionalActionClientArgs) a).args); args.addAll(((OptionalActionClientArgs) a).args);
} }
} }

View file

@ -38,10 +38,9 @@ public final class ServerPinger {
public ServerPinger(ClientProfile profile) { public ServerPinger(ClientProfile profile) {
this(profile.getDefaultServerProfile(), profile.getVersion()); this(profile.getDefaultServerProfile(), profile.getVersion());
} }
public ServerPinger(ClientProfile.ServerProfile profile, ClientProfile.Version version)
{ public ServerPinger(ClientProfile.ServerProfile profile, ClientProfile.Version version) {
if(profile == null) if (profile == null) {
{
throw new NullPointerException("ServerProfile null"); throw new NullPointerException("ServerProfile null");
} }
this.address = profile.toSocketAddress(); this.address = profile.toSocketAddress();

View file

@ -10,6 +10,7 @@ public static class UserInfo {
public String accessToken; public String accessToken;
public PlayerProfile playerProfile; public PlayerProfile playerProfile;
} }
public final UserInfo userInfo; public final UserInfo userInfo;
public CurrentUserRequestEvent(UserInfo userInfo) { public CurrentUserRequestEvent(UserInfo userInfo) {

View file

@ -72,24 +72,23 @@ public final class ClientProfile implements Comparable<ClientProfile> {
@LauncherNetworkAPI @LauncherNetworkAPI
private String mainClass; private String mainClass;
public static class ServerProfile public static class ServerProfile {
{
public String name; public String name;
public String serverAddress; public String serverAddress;
public int serverPort; public int serverPort;
public boolean isDefault = true; public boolean isDefault = true;
public InetSocketAddress toSocketAddress()
{ public InetSocketAddress toSocketAddress() {
return InetSocketAddress.createUnresolved(serverAddress, serverPort); return InetSocketAddress.createUnresolved(serverAddress, serverPort);
} }
} }
@LauncherNetworkAPI @LauncherNetworkAPI
private List<ServerProfile> servers = new ArrayList<>(1); private List<ServerProfile> servers = new ArrayList<>(1);
public ServerProfile getDefaultServerProfile()
{ public ServerProfile getDefaultServerProfile() {
for(ServerProfile profile : servers) for (ServerProfile profile : servers) {
{ if (profile.isDefault) return profile;
if(profile.isDefault) return profile;
} }
return null; return null;
} }
@ -184,6 +183,7 @@ public void updateOptionalGraph() {
} }
} }
} }
@Deprecated @Deprecated
public OptionalFile getOptionalFile(String file, OptionalType type) { public OptionalFile getOptionalFile(String file, OptionalType type) {
for (OptionalFile f : updateOptional) for (OptionalFile f : updateOptional)
@ -220,6 +220,7 @@ public void markOptional(OptionalFile file) {
} }
} }
} }
@Deprecated @Deprecated
public void unmarkOptional(OptionalFile file) { public void unmarkOptional(OptionalFile file) {
if (!file.mark) return; if (!file.mark) return;
@ -246,6 +247,7 @@ public void unmarkOptional(OptionalFile file) {
} }
} }
} }
@Deprecated @Deprecated
public void pushOptionalFile(HashedDir dir, boolean digest) { public void pushOptionalFile(HashedDir dir, boolean digest) {
for (OptionalFile opt : updateOptional) { for (OptionalFile opt : updateOptional) {
@ -255,6 +257,7 @@ public void pushOptionalFile(HashedDir dir, boolean digest) {
} }
} }
} }
@Deprecated @Deprecated
public void pushOptionalJvmArgs(Collection<String> jvmArgs1) { public void pushOptionalJvmArgs(Collection<String> jvmArgs1) {
for (OptionalFile opt : updateOptional) { for (OptionalFile opt : updateOptional) {
@ -263,6 +266,7 @@ public void pushOptionalJvmArgs(Collection<String> jvmArgs1) {
} }
} }
} }
@Deprecated @Deprecated
public void pushOptionalClientArgs(Collection<String> clientArgs1) { public void pushOptionalClientArgs(Collection<String> clientArgs1) {
for (OptionalFile opt : updateOptional) { for (OptionalFile opt : updateOptional) {
@ -271,6 +275,7 @@ public void pushOptionalClientArgs(Collection<String> clientArgs1) {
} }
} }
} }
@Deprecated @Deprecated
public void pushOptionalClassPath(pushOptionalClassPathCallback callback) throws IOException { public void pushOptionalClassPath(pushOptionalClassPathCallback callback) throws IOException {
for (OptionalFile opt : updateOptional) { for (OptionalFile opt : updateOptional) {
@ -284,6 +289,7 @@ public int getServerPort() {
ServerProfile profile = getDefaultServerProfile(); ServerProfile profile = getDefaultServerProfile();
return profile == null ? 25565 : profile.serverPort; return profile == null ? 25565 : profile.serverPort;
} }
@Deprecated @Deprecated
public InetSocketAddress getServerSocketAddress() { public InetSocketAddress getServerSocketAddress() {
return InetSocketAddress.createUnresolved(getServerAddress(), getServerPort()); return InetSocketAddress.createUnresolved(getServerAddress(), getServerPort());

View file

@ -14,17 +14,12 @@ public class OptionalView {
public Set<OptionalFile> all; public Set<OptionalFile> all;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public<T extends OptionalAction> Set<T> getActionsByClass(Class<T> clazz) public <T extends OptionalAction> Set<T> getActionsByClass(Class<T> clazz) {
{
Set<T> results = new HashSet<>(); Set<T> results = new HashSet<>();
for(OptionalFile e : enabled) for (OptionalFile e : enabled) {
{ if (e.actions != null) {
if(e.actions != null) for (OptionalAction a : e.actions) {
{ if (clazz.isAssignableFrom(a.getClass())) {
for(OptionalAction a : e.actions)
{
if(clazz.isAssignableFrom(a.getClass()))
{
results.add((T) a); results.add((T) a);
} }
} }
@ -33,36 +28,29 @@ public<T extends OptionalAction> Set<T> getActionsByClass(Class<T> clazz)
return results; return results;
} }
public Set<OptionalAction> getEnabledActions() public Set<OptionalAction> getEnabledActions() {
{
Set<OptionalAction> results = new HashSet<>(); Set<OptionalAction> results = new HashSet<>();
for(OptionalFile e : enabled) for (OptionalFile e : enabled) {
{ if (e.actions != null) {
if(e.actions != null)
{
results.addAll(e.actions); results.addAll(e.actions);
} }
} }
return results; return results;
} }
public Set<OptionalAction> getDisabledActions() public Set<OptionalAction> getDisabledActions() {
{
Set<OptionalAction> results = new HashSet<>(); Set<OptionalAction> results = new HashSet<>();
for(OptionalFile e : all) for (OptionalFile e : all) {
{ if (enabled.contains(e)) continue;
if(enabled.contains(e)) continue; if (e.actions != null) {
if(e.actions != null)
{
results.addAll(e.actions); results.addAll(e.actions);
} }
} }
return results; return results;
} }
public void enable(OptionalFile file) public void enable(OptionalFile file) {
{ if (enabled.contains(file)) return;
if(enabled.contains(file)) return;
enabled.add(file); enabled.add(file);
file.watchEvent(true); file.watchEvent(true);
if (file.dependencies != null) { if (file.dependencies != null) {
@ -78,9 +66,9 @@ public void enable(OptionalFile file)
} }
} }
} }
public void disable(OptionalFile file)
{ public void disable(OptionalFile file) {
if(!enabled.remove(file)) return; if (!enabled.remove(file)) return;
file.watchEvent(false); file.watchEvent(false);
Set<OptionalFile> dependenciesCount = dependenciesCountMap.get(file); Set<OptionalFile> dependenciesCount = dependenciesCountMap.get(file);
if (dependenciesCount != null) { if (dependenciesCount != null) {
@ -103,16 +91,15 @@ public void disable(OptionalFile file)
} }
} }
} }
public OptionalView(ClientProfile profile)
{ public OptionalView(ClientProfile profile) {
this.all = profile.getOptional(); this.all = profile.getOptional();
for(OptionalFile f : this.all) for (OptionalFile f : this.all) {
{ if (f.mark) enable(f);
if(f.mark) enable(f);
} }
} }
public OptionalView(OptionalView view)
{ public OptionalView(OptionalView view) {
this.enabled = new HashSet<>(view.enabled); this.enabled = new HashSet<>(view.enabled);
this.dependenciesCountMap = new HashMap<>(view.dependenciesCountMap); this.dependenciesCountMap = new HashMap<>(view.dependenciesCountMap);
this.all = view.all; this.all = view.all;

View file

@ -5,10 +5,9 @@
public class OptionalAction { public class OptionalAction {
public static final ProviderMap<OptionalAction> providers = new ProviderMap<>(); public static final ProviderMap<OptionalAction> providers = new ProviderMap<>();
private static boolean registerProviders = false; private static boolean registerProviders = false;
public static void registerProviders()
{ public static void registerProviders() {
if(!registerProviders) if (!registerProviders) {
{
providers.register("file", OptionalActionFile.class); providers.register("file", OptionalActionFile.class);
providers.register("clientArgs", OptionalActionClientArgs.class); providers.register("clientArgs", OptionalActionClientArgs.class);
providers.register("jvmArgs", OptionalActionJvmArgs.class); providers.register("jvmArgs", OptionalActionJvmArgs.class);

View file

@ -7,10 +7,10 @@
public class OptionalActionFile extends OptionalAction { public class OptionalActionFile extends OptionalAction {
public Map<String, String> files; public Map<String, String> files;
public void injectToHashedDir(HashedDir dir)
{ public void injectToHashedDir(HashedDir dir) {
if(files == null) return; if (files == null) return;
files.forEach((k,v) -> { files.forEach((k, v) -> {
HashedDir.FindRecursiveResult firstPath = dir.findRecursive(k); HashedDir.FindRecursiveResult firstPath = dir.findRecursive(k);
if (v != null && !v.isEmpty()) { if (v != null && !v.isEmpty()) {
LogHelper.dev("Debug findRecursive: name %s, parent: ", firstPath.name, firstPath.parent == null ? "null" : "not null", firstPath.entry == null ? "null" : "not null"); LogHelper.dev("Debug findRecursive: name %s, parent: ", firstPath.name, firstPath.parent == null ? "null" : "not null", firstPath.entry == null ? "null" : "not null");
@ -20,10 +20,10 @@ public void injectToHashedDir(HashedDir dir)
} }
}); });
} }
public void disableInHashedDir(HashedDir dir)
{ public void disableInHashedDir(HashedDir dir) {
if(files == null) return; if (files == null) return;
files.forEach((k,v) -> { files.forEach((k, v) -> {
HashedDir.FindRecursiveResult firstPath = dir.findRecursive(k); HashedDir.FindRecursiveResult firstPath = dir.findRecursive(k);
firstPath.parent.remove(firstPath.name); firstPath.parent.remove(firstPath.name);
}); });

View file

@ -5,6 +5,7 @@
public class Auth2FAPassword implements AuthRequest.AuthPasswordInterface { public class Auth2FAPassword implements AuthRequest.AuthPasswordInterface {
public AuthRequest.AuthPasswordInterface firstPassword; public AuthRequest.AuthPasswordInterface firstPassword;
public AuthRequest.AuthPasswordInterface secondPassword; public AuthRequest.AuthPasswordInterface secondPassword;
@Override @Override
public boolean check() { public boolean check() {
return firstPassword != null && firstPassword.check() && secondPassword != null && secondPassword.check(); return firstPassword != null && firstPassword.check() && secondPassword != null && secondPassword.check();

View file

@ -6,6 +6,7 @@ public class AuthSignaturePassword implements AuthRequest.AuthPasswordInterface
public byte[] signature; public byte[] signature;
public byte[] publicKey; public byte[] publicKey;
public byte[] salt; public byte[] salt;
@Override @Override
public boolean check() { public boolean check() {
return true; return true;

View file

@ -4,6 +4,7 @@
public class AuthTOTPPassword implements AuthRequest.AuthPasswordInterface { public class AuthTOTPPassword implements AuthRequest.AuthPasswordInterface {
public String totp; public String totp;
@Override @Override
public boolean check() { public boolean check() {
return true; return true;

View file

@ -11,19 +11,19 @@ public String getType() {
return "pingServerReport"; return "pingServerReport";
} }
public static class PingServerReport public static class PingServerReport {
{
public final String name; public final String name;
public final int maxPlayers; // player slots public final int maxPlayers; // player slots
public final int playersOnline; public final int playersOnline;
public static class UsernameInfo
{ public static class UsernameInfo {
public final String username; public final String username;
public UsernameInfo(String username) { public UsernameInfo(String username) {
this.username = username; this.username = username;
} }
} }
//Server addional info //Server addional info
public double tps; //Server tps public double tps; //Server tps
public List<UsernameInfo> users; public List<UsernameInfo> users;
@ -34,6 +34,7 @@ public PingServerReport(String name, int maxPlayers, int playersOnline) {
this.playersOnline = playersOnline; this.playersOnline = playersOnline;
} }
} }
public final String name; public final String name;
public final PingServerReport data; public final PingServerReport data;

View file

@ -100,13 +100,13 @@ public void removeR(String name) {
} }
} }
} }
public void moveTo(String elementName, HashedDir target, String targetElementName)
{ public void moveTo(String elementName, HashedDir target, String targetElementName) {
HashedEntry entry = map.remove(elementName); HashedEntry entry = map.remove(elementName);
target.map.put(targetElementName, entry); target.map.put(targetElementName, entry);
} }
public static class FindRecursiveResult
{ public static class FindRecursiveResult {
public final HashedDir parent; public final HashedDir parent;
public final HashedEntry entry; public final HashedEntry entry;
public final String name; public final String name;
@ -117,8 +117,8 @@ public FindRecursiveResult(HashedDir parent, HashedEntry entry, String name) {
this.name = name; this.name = name;
} }
} }
public FindRecursiveResult findRecursive(String path)
{ public FindRecursiveResult findRecursive(String path) {
StringTokenizer t = new StringTokenizer(path, "/"); StringTokenizer t = new StringTokenizer(path, "/");
HashedDir current = this; HashedDir current = this;
HashedEntry entry = null; HashedEntry entry = null;
@ -126,16 +126,14 @@ public FindRecursiveResult findRecursive(String path)
while (t.hasMoreTokens()) { while (t.hasMoreTokens()) {
name = t.nextToken(); name = t.nextToken();
HashedEntry e = current.map.get(name); HashedEntry e = current.map.get(name);
if(e == null && !t.hasMoreTokens()) if (e == null && !t.hasMoreTokens()) {
{
break; break;
} }
if (e.getType() == Type.DIR) { if (e.getType() == Type.DIR) {
if(!t.hasMoreTokens()) { if (!t.hasMoreTokens()) {
entry = e; entry = e;
break; break;
} } else {
else {
current = ((HashedDir) e); current = ((HashedDir) e);
} }
} else { } else {

View file

@ -54,8 +54,7 @@ public R deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext
Class<? extends R> cls = providerMap.getClass(typename); Class<? extends R> cls = providerMap.getClass(typename);
if (cls == null) { if (cls == null) {
//if (printErrorIfUnknownType) LogHelper.error("%s %s not found", name, typename); //if (printErrorIfUnknownType) LogHelper.error("%s %s not found", name, typename);
if(defaultClass != null) if (defaultClass != null) {
{
return context.deserialize(json, defaultClass); return context.deserialize(json, defaultClass);
} }
return null; return null;

@ -1 +1 @@
Subproject commit aab3e310b3b4b396c80a3aad3f6f9386cf427c39 Subproject commit 4795b7a967af69ddea48116c718bb32b96e43f83