Added untested rate limits

This commit is contained in:
Anuken
2020-01-07 14:16:48 -05:00
parent 3e0556de05
commit 1f3bab5fa3
6 changed files with 53 additions and 13 deletions

View File

@@ -160,7 +160,7 @@ public class NetClient implements ApplicationListener{
throw new ValidateException(player, "Player has sent a message above the text limit.");
}
String original = message;
Events.fire(new PlayerChatEvent(player, message));
//check if it's a command
CommandResponse response = netServer.clientCommands.handleMessage(message, player);
@@ -197,8 +197,6 @@ public class NetClient implements ApplicationListener{
player.sendMessage(text);
}
}
Events.fire(new PlayerChatEvent(player, message, original));
}
public static String colorizeName(int id, String name){

View File

@@ -35,7 +35,7 @@ import static mindustry.Vars.*;
public class NetServer implements ApplicationListener{
private final static int maxSnapshotSize = 430, timerBlockSync = 0;
private final static float serverSyncTime = 12, kickDuration = 30 * 1000, blockSyncTime = 60 * 8;
private final static float serverSyncTime = 12, blockSyncTime = 60 * 8;
private final static Vec2 vector = new Vec2();
private final static Rect viewport = new Rect();
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
@@ -115,7 +115,7 @@ public class NetServer implements ApplicationListener{
return;
}
if(Time.millis() - info.lastKicked < kickDuration){
if(Time.millis() < info.lastKicked){
con.kick(KickReason.recentKick);
return;
}

View File

@@ -64,13 +64,10 @@ public class EventType{
public static class PlayerChatEvent{
public final Player player;
public final String message;
/** The original, unfiltered message. */
public final String originalMessage;
public PlayerChatEvent(Player player, String message, String originalMessage){
public PlayerChatEvent(Player player, String message){
this.player = player;
this.message = message;
this.originalMessage = originalMessage;
}
}

View File

@@ -2,6 +2,7 @@ package mindustry.net;
import arc.*;
import arc.struct.*;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import mindustry.*;
import mindustry.annotations.Annotations.*;
@@ -19,6 +20,38 @@ public class Administration{
public Administration(){
load();
//anti-spam
addChatFilter((player, message) -> {
long resetTime = Config.messageRateLimit.num() * 1000;
if(Config.antiSpam.bool() && !player.isLocal && !player.isAdmin){
//prevent people from spamming messages quickly
if(resetTime > 0 && Time.timeSinceMillis(player.getInfo().lastMessageTime) < resetTime){
//supress message
player.sendMessage("[scarlet]You may only send messages every " + Config.messageRateLimit.num() + " seconds.");
player.getInfo().messageInfractions ++;
//kick player for spamming and prevent connection if they've done this several times
if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){
player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2);
}
player.lastText = message;
return null;
}else{
player.getInfo().messageInfractions = 0;
}
//prevent players from sending the same message twice in the span of 50 seconds
if(message.equals(player.lastText) && Time.timeSinceMillis(player.getInfo().lastMessageTime) < 1000 * 50){
player.sendMessage("[scarlet]You may not send the same message twice.");
return null;
}
player.lastText = message;
player.getInfo().lastMessageTime = Time.millis();
}
return message;
});
}
/** Adds a chat filter. This will transform the chat messages of every player.
@@ -326,6 +359,9 @@ public class Administration{
crashReport("Whether to send crash reports.", false, "crashreport"),
logging("Whether to log everything to files.", true),
strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true),
antiSpam("Whether spammers are automatically kicked and rate-limited.", true),
messageRateLimit("Message rate limit in seconds. 0 to disable.", 0),
messageSpamKick("How many times a player must send a message before the cooldown to get kicked. 0 to disable.", 3),
socketInput("Allows a local application to control this server through a local TCP socket.", false, "socket", () -> Events.fire(Trigger.socketConfigChanged)),
socketInputPort("The port for socket input.", 6859, () -> Events.fire(Trigger.socketConfigChanged)),
socketInputAddress("The bind address for socket input.", "localhost", () -> Events.fire(Trigger.socketConfigChanged)),
@@ -402,7 +438,11 @@ public class Administration{
public int timesKicked;
public int timesJoined;
public boolean banned, admin;
public long lastKicked; //last kicked timestamp
public long lastKicked; //last kicked time to expiration
public transient long lastMessageTime;
public transient String lastSentMessage;
public transient int messageInfractions;
PlayerInfo(String id){
this.id = id;

View File

@@ -37,7 +37,7 @@ public abstract class NetConnection{
if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){
PlayerInfo info = netServer.admins.getInfo(player.uuid);
info.timesKicked++;
info.lastKicked = Math.max(Time.millis(), info.lastKicked);
info.lastKicked = Math.max(Time.millis() + 30 * 1000, info.lastKicked);
}
Call.onKick(this, reason);
@@ -49,12 +49,17 @@ public abstract class NetConnection{
/** Kick with an arbitrary reason. */
public void kick(String reason){
kick(reason, 30 * 1000);
}
/** Kick with an arbitrary reason, and a kick duration in milliseconds. */
public void kick(String reason, int kickDuration){
Log.info("Kicking connection {0}; Reason: {1}", address, reason.replace("\n", " "));
if(player != null && player.uuid != null){
PlayerInfo info = netServer.admins.getInfo(player.uuid);
info.timesKicked++;
info.lastKicked = Math.max(Time.millis(), info.lastKicked);
info.lastKicked = Math.max(Time.millis() + kickDuration, info.lastKicked);
}
Call.onKick(this, reason);