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

@@ -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);