This commit is contained in:
Dawson
2022-09-06 13:25:14 -04:00
parent 77542ebad7
commit 7b932060d4
16 changed files with 562 additions and 55 deletions
@@ -27,6 +27,7 @@ import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.TickTimer;
import dev.brighten.ac.utils.world.WorldInfo;
import dev.brighten.loader.LoaderPlugin;
import dev.brighten.log.socket.LogSocketManager;
import lombok.Getter;
import lombok.experimental.PackagePrivate;
import org.bukkit.Bukkit;
@@ -61,6 +62,7 @@ public class Anticheat extends LoaderPlugin {
private KeepaliveProcessor keepaliveProcessor;
private PacketHandler packetHandler;
private LoggerManager logManager;
public LogSocketManager socketManager;
private int currentTick;
private Deque<Runnable> onTickEnd = new LinkedList<>();
private ServerInjector injector;
@@ -116,6 +118,8 @@ public class Anticheat extends LoaderPlugin {
this.checkManager = new CheckManager();
this.playerRegistry = new PlayerRegistry();
this.packetHandler = new PacketHandler();
this.socketManager = new LogSocketManager();
socketManager.startSockets();
logManager = new LoggerManager();
keepaliveProcessor.start();
@@ -154,6 +158,8 @@ public class Anticheat extends LoaderPlugin {
ProtocolAPI.INSTANCE = null;
tps = null;
socketManager.shutdownSockets();
logManager.shutDown();
Bukkit.getScheduler().cancelTasks(getPluginInstance());
@@ -262,7 +262,10 @@ public class Horizontal extends Check {
} else debug("bad movement");
} else if (buffer > 0) buffer -= 0.05f;
debug("smallest=%s efcs=[%s] pm=%.5f dxz=%.5f b=%.1f", smallestDelta, player.getPotionHandler().potionEffects.stream().map(pe -> pe.getType().getName() + ";" + pe.getAmplifier()).collect(Collectors.joining(", ")), pmotion,
debug("smallest=%s sp=%s efcs=[%s] pm=%.5f dxz=%.5f b=%.1f", smallestDelta,
player.getInfo().isSprinting(), player.getPotionHandler().potionEffects.stream()
.map(pe -> pe.getType().getName() + ";" + pe.getAmplifier())
.collect(Collectors.joining(", ")), pmotion,
player.getMovement().getDeltaXZ(), buffer);
}
lastLastClientGround = player.getMovement().getFrom().isOnGround();
@@ -185,7 +185,7 @@ public class AnticheatCommand extends BaseCommand {
return crc.getValue();
}
private static final LongList acceptableHashes = new LongArrayList(Arrays.asList(3912178420L));
private static final LongList acceptableHashes = new LongArrayList(Arrays.asList(3912178420L, 2719903731L));
@Subcommand("alerts")
@CommandPermission("anticheat.command.alerts")
@@ -105,7 +105,7 @@ public class PlayerRegistry {
return crc.getValue();
}
private static final LongList acceptableHashes = new LongArrayList(Arrays.asList(3912178420L));
private static final LongList acceptableHashes = new LongArrayList(Arrays.asList(3912178420L, 2719903731L));
public Optional<APlayer> getPlayer(UUID uuid) {
return Optional.ofNullable(aplayerMap.get(uuid.hashCode()));
@@ -3,22 +3,27 @@ package dev.brighten.ac.logging;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.logging.sql.ExecutableStatement;
import dev.brighten.ac.logging.sql.MySQL;
import dev.brighten.ac.logging.sql.Query;
import dev.brighten.ac.logging.sql.ResultSetIterator;
import dev.brighten.ac.utils.RunUtils;
import dev.brighten.log.socket.OutRequest;
import dev.brighten.log.socket.RequestType;
import dev.brighten.log.utils.EncryptionUtils;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class LoggerManager {
private final Deque<Log> logList = new LinkedList<>();
private KeyPair keys;
private PublicKey encryptKey;
/*
* Structure of Log
@@ -26,57 +31,68 @@ public class LoggerManager {
*/
public void init() {
// Starting up H2
MySQL.initH2();
Anticheat.INSTANCE.getLogger().info("Generating RSA...");
keys = EncryptionUtils.Companion.geneateRsa();
try {
Anticheat.INSTANCE.getLogger().info("Sending init request to log server...");
OutRequest request = new OutRequest(RequestType.INITIALIZE.toString(), "localhost", null);
Query.prepare("CREATE TABLE IF NOT EXISTS `logs` (" +
"`id` INT NOT NULL AUTO_INCREMENT," +
"`uuid` INT NOT NULL," +
"`check` VARCHAR(32) NOT NULL," +
"`vl` FLOAT NOT NULL," +
"`data` MEDIUMTEXT NOT NULL," +
"`time` TIMESTAMP NOT NULL," +
"PRIMARY KEY (`id`)" +
");").execute();
String encoded = Base64.getEncoder().encodeToString(keys.getPublic().getEncoded());
System.out.println(encoded);
request.getObjects().writeUTF(encoded);
Query.prepare("create index if not exists `uuid_1` on `logs` (`uuid`)")
.execute();
Query.prepare("create index if not exists `uuid_check_1` on `logs` (`uuid`, `check`)")
.execute();
request.write();
Anticheat.INSTANCE.getScheduler().scheduleAtFixedRate(() -> {
if(logList.size() > 0) {
synchronized (logList) {
final StringBuilder values = new StringBuilder();
Anticheat.INSTANCE.getLogger().info("Sent!");
} catch (IOException e) {
throw new RuntimeException(e);
}
List<Object> objectsToInsert = new ArrayList<>();
Log log = null;
int amount = 0;
while((log = logList.poll()) != null) {
objectsToInsert.add(log.getUuid().hashCode());
objectsToInsert.add(log.getCheckId());
objectsToInsert.add(log.getVl());
objectsToInsert.add(log.getData());
objectsToInsert.add(new Timestamp(log.getTime()));
Anticheat.INSTANCE.getSocketManager().onInputReceived(event -> {
if(event.getRequest().getHeader().equals(RequestType.INITIALIZE.toString())) {
System.out.println("Received key from server!");
ObjectInputStream objectStream = event.getRequest().getObjects();
try {
String publicKeyString = objectStream.readUTF();
if(++amount >= 150) break;
}
for (int i = 0; i < amount; i++) {
values.append(i > 0 ? "," : "").append("(?, ?, ?, ?, ?)");
}
ExecutableStatement statement = Query.prepare("INSERT INTO `logs` " +
"(`uuid`,`check`,`vl`,`data`,`time`) VALUES" + values.toString())
.append(objectsToInsert.toArray());
statement.execute();
Anticheat.INSTANCE.getLogger().info("Saved " + amount + " logs!");
objectsToInsert.clear();
encryptKey = EncryptionUtils.Companion.publicKeyFromString(publicKeyString);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}, 5, 10, TimeUnit.SECONDS);
});
RunUtils.taskTimerAsync(() -> {
System.out.println("Running ping!");
OutRequest request = new OutRequest(RequestType.PING.toString(),
"localhost",
encryptKey);
try {
request.getObjects().writeLong(System.currentTimeMillis());
request.write();
} catch (IOException e) {
throw new RuntimeException(e);
}
}, 80, 40);
Anticheat.INSTANCE.socketManager.onInputReceived(event -> {
if(event.getRequest().getHeader().equals(RequestType.PING.toString())) {
ObjectInputStream objects = event.getRequest().getObjects(keys.getPrivate());
try {
long serverTime = objects.readLong();
long extense = objects.readLong();
long ping = System.currentTimeMillis() - serverTime + extense;
System.out.println("Ping: " + ping + "ms");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
public void insertLog(APlayer player, CheckData checkData, float vl, long time, String data) {
@@ -94,6 +110,6 @@ public class LoggerManager {
}
public void shutDown() {
MySQL.shutdown();
}
}
@@ -0,0 +1,92 @@
package dev.brighten.ac.utils;
public final class Base64 {
private static final int BYTES_PER_UNENCODED_BLOCK = 3;
private static final int BYTES_PER_ENCODED_BLOCK = 4;
private static final int SIX_BIT_MASK = 63;
private static final byte PAD = 61;
private static final byte[] ENCODE_TABLE = new byte[]{65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47};
private static final int[] DECODE_TABLE = new int[128];
public static byte[] decode(String s) {
int delta = s.endsWith("==") ? 2 : (s.endsWith("=") ? 1 : 0);
byte[] buffer = new byte[s.length() * 3 / 4 - delta];
int mask = 255;
int pos = 0;
for(int i = 0; i < s.length(); i += 4) {
int c0 = DECODE_TABLE[s.charAt(i)];
int c1 = DECODE_TABLE[s.charAt(i + 1)];
buffer[pos++] = (byte)((c0 << 2 | c1 >> 4) & mask);
if (pos >= buffer.length) {
return buffer;
}
int c2 = DECODE_TABLE[s.charAt(i + 2)];
buffer[pos++] = (byte)((c1 << 4 | c2 >> 2) & mask);
if (pos >= buffer.length) {
return buffer;
}
int c3 = DECODE_TABLE[s.charAt(i + 3)];
buffer[pos++] = (byte)((c2 << 6 | c3) & mask);
}
return buffer;
}
public static String encode(byte[] in) {
int modulus = 0;
int bitWorkArea = 0;
int numEncodedBytes = in.length / 3 * 4 + (in.length % 3 == 0 ? 0 : 4);
byte[] buffer = new byte[numEncodedBytes];
int pos = 0;
byte[] var6 = in;
int var7 = in.length;
for(int var8 = 0; var8 < var7; ++var8) {
int b = var6[var8];
modulus = (modulus + 1) % 3;
if (b < 0) {
b += 256;
}
bitWorkArea = (bitWorkArea << 8) + b;
if (0 == modulus) {
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 18 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 12 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 6 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea & 63];
}
}
switch (modulus) {
case 1:
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 2 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea << 4 & 63];
buffer[pos++] = 61;
buffer[pos] = 61;
break;
case 2:
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 10 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 4 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea << 2 & 63];
buffer[pos] = 61;
}
return byteArrayToString(buffer);
}
private static String byteArrayToString(byte[] buffer) {
return new String(buffer, 0, 0, buffer.length);
}
private Base64() {
}
static {
for(int i = 0; i < ENCODE_TABLE.length; DECODE_TABLE[ENCODE_TABLE[i]] = i++) {
}
}
}
@@ -92,7 +92,7 @@ public class IntegrityCheck {
return crc.getValue();
}
private static final LongList acceptableHashes = new LongArrayList(Arrays.asList(3912178420L));
private static final LongList acceptableHashes = new LongArrayList(Arrays.asList(3912178420L, 2719903731L));
}
@@ -0,0 +1,50 @@
package dev.brighten.ac.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
public class StreamUtils {
public static void streamCopy(InputStream in, OutputStream out) throws IOException {
assert (in != null);
assert (out != null);
ReadableByteChannel inChannel = Channels.newChannel(in);
WritableByteChannel outChannel = Channels.newChannel(out);
channelCopy(inChannel, outChannel);
}
/**
* A fast method to copy bytes from one channel to another; uses direct 16k
* buffers to minimize copies and OS overhead.
* @author http://thomaswabner.wordpress.com/2007/10/09/fast-stream-copy-using-javanio-channels/
* @param src - a non-null readable bytechannel to read the data from
* @param dest - a non-null writeable byte channel to write the data to
*/
public static void channelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException {
assert (src != null);
assert (dest != null);
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1) {
// prepare the buffer to be drained
buffer.flip();
// write to the channel, may block
dest.write(buffer);
// If partial transfer, shift remainder down
// If buffer is empty, same as doing clear()
buffer.compact();
}
// EOF will leave buffer in fill state
buffer.flip();
// make sure the buffer is fully drained.
while (buffer.hasRemaining()) {
dest.write(buffer);
}
}
}