Added untested rate limits
This commit is contained in:
@@ -160,7 +160,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
throw new ValidateException(player, "Player has sent a message above the text limit.");
|
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
|
//check if it's a command
|
||||||
CommandResponse response = netServer.clientCommands.handleMessage(message, player);
|
CommandResponse response = netServer.clientCommands.handleMessage(message, player);
|
||||||
@@ -197,8 +197,6 @@ public class NetClient implements ApplicationListener{
|
|||||||
player.sendMessage(text);
|
player.sendMessage(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Events.fire(new PlayerChatEvent(player, message, original));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String colorizeName(int id, String name){
|
public static String colorizeName(int id, String name){
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import static mindustry.Vars.*;
|
|||||||
|
|
||||||
public class NetServer implements ApplicationListener{
|
public class NetServer implements ApplicationListener{
|
||||||
private final static int maxSnapshotSize = 430, timerBlockSync = 0;
|
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 Vec2 vector = new Vec2();
|
||||||
private final static Rect viewport = new Rect();
|
private final static Rect viewport = new Rect();
|
||||||
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
|
/** 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Time.millis() - info.lastKicked < kickDuration){
|
if(Time.millis() < info.lastKicked){
|
||||||
con.kick(KickReason.recentKick);
|
con.kick(KickReason.recentKick);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,13 +64,10 @@ public class EventType{
|
|||||||
public static class PlayerChatEvent{
|
public static class PlayerChatEvent{
|
||||||
public final Player player;
|
public final Player player;
|
||||||
public final String message;
|
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.player = player;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.originalMessage = originalMessage;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mindustry.net;
|
|||||||
|
|
||||||
import arc.*;
|
import arc.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
import arc.util.ArcAnnotate.*;
|
import arc.util.ArcAnnotate.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
@@ -19,6 +20,38 @@ public class Administration{
|
|||||||
|
|
||||||
public Administration(){
|
public Administration(){
|
||||||
load();
|
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.
|
/** 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"),
|
crashReport("Whether to send crash reports.", false, "crashreport"),
|
||||||
logging("Whether to log everything to files.", true),
|
logging("Whether to log everything to files.", true),
|
||||||
strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", 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)),
|
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)),
|
socketInputPort("The port for socket input.", 6859, () -> Events.fire(Trigger.socketConfigChanged)),
|
||||||
socketInputAddress("The bind address for socket input.", "localhost", () -> 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 timesKicked;
|
||||||
public int timesJoined;
|
public int timesJoined;
|
||||||
public boolean banned, admin;
|
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){
|
PlayerInfo(String id){
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public abstract class NetConnection{
|
|||||||
if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){
|
if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){
|
||||||
PlayerInfo info = netServer.admins.getInfo(player.uuid);
|
PlayerInfo info = netServer.admins.getInfo(player.uuid);
|
||||||
info.timesKicked++;
|
info.timesKicked++;
|
||||||
info.lastKicked = Math.max(Time.millis(), info.lastKicked);
|
info.lastKicked = Math.max(Time.millis() + 30 * 1000, info.lastKicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
Call.onKick(this, reason);
|
Call.onKick(this, reason);
|
||||||
@@ -49,12 +49,17 @@ public abstract class NetConnection{
|
|||||||
|
|
||||||
/** Kick with an arbitrary reason. */
|
/** Kick with an arbitrary reason. */
|
||||||
public void kick(String 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", " "));
|
Log.info("Kicking connection {0}; Reason: {1}", address, reason.replace("\n", " "));
|
||||||
|
|
||||||
if(player != null && player.uuid != null){
|
if(player != null && player.uuid != null){
|
||||||
PlayerInfo info = netServer.admins.getInfo(player.uuid);
|
PlayerInfo info = netServer.admins.getInfo(player.uuid);
|
||||||
info.timesKicked++;
|
info.timesKicked++;
|
||||||
info.lastKicked = Math.max(Time.millis(), info.lastKicked);
|
info.lastKicked = Math.max(Time.millis() + kickDuration, info.lastKicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
Call.onKick(this, reason);
|
Call.onKick(this, reason);
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
archash=c365173e586b84c7edd062d82675001c7b96b0b8
|
archash=9f70d5a39a910bd855430d74e41d0b8753b47442
|
||||||
|
|||||||
Reference in New Issue
Block a user