Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ plugins {

repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}

dependencies {
implementation files("libs/craftbukkit-1060.jar")
implementation files("libs/Essentials.jar")
implementation 'com.github.zavdav:ZCore:1.0.0-rc1'
}

File ymlFile = file('src/main/resources/plugin.yml') as File
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public AboutCommand(ChatGuard plugin) {
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
// Contributors: If you've contributed code, you can add your name here to be credited
List<String> contributors = Arrays.asList(
"moderator_man"
"moderator_man",
"zavdav"
);
AboutUtil.aboutPlugin(sender, plugin, contributors);
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ public static int getStrike(Player player) {

public static String getMuteDuration(String playerName) {
return ChatGuard.getConfig().getString(String.format(
"filter.essentials-mute.duration.s%d",
"filter.auto-mute.duration.s%d",
ChatGuard.getStrikes().getInt(playerName, 0)
));
}

public static String getMuteDuration(Player player) {
return ChatGuard.getConfig().getString(String.format(
"filter.essentials-mute.duration.s%d",
"filter.auto-mute.duration.s%d",
ChatGuard.getStrikes().getInt(player.getName(), 0)
));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package io.github.aleksandarharalanov.chatguard.core.misc;

import com.earth2me.essentials.User;
import io.github.aleksandarharalanov.chatguard.core.security.penalty.MuteEnforcer;
import io.github.aleksandarharalanov.chatguard.util.misc.ColorUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public final class TimeFormatter {

private TimeFormatter() {}

public static void printFormattedMuteDuration(User user) {
long remainingMillis = user.getMuteTimeout() - System.currentTimeMillis();
public static void printFormattedMuteDuration(String username) {
long remainingMillis = MuteEnforcer.muteHandler.getUserMuteTimeout(username) - System.currentTimeMillis();

Map<String, Integer> timeUnits = new LinkedHashMap<>();
timeUnits.put("d.", (int) (remainingMillis / (1000 * 60 * 60 * 24)));
Expand All @@ -25,8 +31,91 @@ public static void printFormattedMuteDuration(User user) {
.map(entry -> entry.getValue() + entry.getKey())
.collect(Collectors.joining(" ", "", ""));

user.sendMessage(ColorUtil.translateColorCodes(String.format(
Player player = Bukkit.getServer().getPlayer(username);
player.sendMessage(ColorUtil.translateColorCodes(String.format(
"&7Expires in %s", formattedTime
)));
}

// Essentials code: com.earth2me.essentials.Util.parseDateDiff
public static long parseDateDiff(String time, boolean future) throws Exception {
Pattern timePattern = Pattern.compile(
"(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?"
+ "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?"
+ "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?"
+ "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?"
+ "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?"
+ "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?"
+ "(?:([0-9]+)\\s*(?:s[a-z]*)?)?", Pattern.CASE_INSENSITIVE);
Matcher m = timePattern.matcher(time);
int years = 0;
int months = 0;
int weeks = 0;
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
boolean found = false;
while (m.find()) {
if (m.group() == null || m.group().isEmpty()) {
continue;
}
for (int i = 0; i < m.groupCount(); i++) {
if (m.group(i) != null && !m.group(i).isEmpty()) {
found = true;
break;
}
}
if (found) {
if (m.group(1) != null && !m.group(1).isEmpty()) {
years = Integer.parseInt(m.group(1));
}
if (m.group(2) != null && !m.group(2).isEmpty()) {
months = Integer.parseInt(m.group(2));
}
if (m.group(3) != null && !m.group(3).isEmpty()) {
weeks = Integer.parseInt(m.group(3));
}
if (m.group(4) != null && !m.group(4).isEmpty()) {
days = Integer.parseInt(m.group(4));
}
if (m.group(5) != null && !m.group(5).isEmpty()) {
hours = Integer.parseInt(m.group(5));
}
if (m.group(6) != null && !m.group(6).isEmpty()) {
minutes = Integer.parseInt(m.group(6));
}
if (m.group(7) != null && !m.group(7).isEmpty()) {
seconds = Integer.parseInt(m.group(7));
}
break;
}
}
if (!found) {
throw new Exception();
}
Calendar c = new GregorianCalendar();
if (years > 0) {
c.add(Calendar.YEAR, years * (future ? 1 : -1));
}
if (months > 0) {
c.add(Calendar.MONTH, months * (future ? 1 : -1));
}
if (weeks > 0) {
c.add(Calendar.WEEK_OF_YEAR, weeks * (future ? 1 : -1));
}
if (days > 0) {
c.add(Calendar.DAY_OF_MONTH, days * (future ? 1 : -1));
}
if (hours > 0) {
c.add(Calendar.HOUR_OF_DAY, hours * (future ? 1 : -1));
}
if (minutes > 0) {
c.add(Calendar.MINUTE, minutes * (future ? 1 : -1));
}
if (seconds > 0) {
c.add(Calendar.SECOND, seconds * (future ? 1 : -1));
}
return c.getTimeInMillis();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static void handleBlockedContent(LogType logType, Player player, String c
ConsoleLogger.log(logType, player, content);
FileLogger.log(logType, player, content);
DiscordLogger.log(logType, player, content, trigger);
MuteEnforcer.processEssentialsMute(logType, player);
MuteEnforcer.processMute(logType, player);
StrikeEnforcer.incrementStrikeTier(logType, player);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.github.aleksandarharalanov.chatguard.core.security.penalty;

import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;

public class EssentialsMuteHandler implements MuteHandler {

private final Essentials essentials;

public EssentialsMuteHandler(Essentials essentials) {
this.essentials = essentials;
}

@Override
public boolean isUserMuted(String username) {
User user = essentials.getUser(username);
return user.isMuted();
}

@Override
public long getUserMuteTimeout(String username) {
User user = essentials.getUser(username);
return user.getMuteTimeout();
}

@Override
public void setUserMuteTimeout(String username, long timestamp) {
User user = essentials.getUser(username);
user.setMuteTimeout(timestamp);
user.setMuted(true);
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
package io.github.aleksandarharalanov.chatguard.core.security.penalty;

import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;
import com.earth2me.essentials.Util;
import io.github.aleksandarharalanov.chatguard.ChatGuard;
import io.github.aleksandarharalanov.chatguard.core.data.PenaltyData;
import io.github.aleksandarharalanov.chatguard.core.log.LogAttribute;
import io.github.aleksandarharalanov.chatguard.core.log.LogType;
import io.github.aleksandarharalanov.chatguard.core.misc.TimeFormatter;
import io.github.aleksandarharalanov.chatguard.util.misc.ColorUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;

public final class MuteEnforcer {

public static final MuteHandler muteHandler;

static {
PluginManager pM = Bukkit.getServer().getPluginManager();
if (pM.getPlugin("Essentials") != null) {
muteHandler = new EssentialsMuteHandler((Essentials) pM.getPlugin("Essentials"));
} else if (pM.getPlugin("ZCore") != null) {
muteHandler = new ZCoreMuteHandler();
} else {
muteHandler = null;
}
}

private MuteEnforcer() {}

public static void processEssentialsMute(LogType logType, Player player) {
boolean isEssentialsMuteEnabled = ChatGuard.getConfig().getBoolean("filter.essentials-mute.enabled", true);
if (!isEssentialsMuteEnabled) return;
public static void processMute(LogType logType, Player player) {
boolean isAutomaticMuteEnabled = ChatGuard.getConfig().getBoolean("filter.auto-mute.enabled", true);
if (!isAutomaticMuteEnabled) return;

if (!logType.hasAttribute(LogAttribute.MUTE) || logType == LogType.NAME) return;

Essentials essentials = (Essentials) Bukkit.getServer().getPluginManager().getPlugin("Essentials");
if (essentials == null || !essentials.isEnabled()) return;
if (muteHandler == null) return;

User user = essentials.getUser(player.getName());
try {
user.setMuteTimeout(Util.parseDateDiff(PenaltyData.getMuteDuration(player), true));
muteHandler.setUserMuteTimeout(
player.getName(),
TimeFormatter.parseDateDiff(PenaltyData.getMuteDuration(player), true));
} catch (Exception e) {
e.printStackTrace();
return;
}
user.setMuted(true);

Bukkit.getServer().broadcastMessage(ColorUtil.translateColorCodes(String.format(
"&c[ChatGuard] %s muted for %s. by system; content has bad words.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.aleksandarharalanov.chatguard.core.security.penalty;

public interface MuteHandler {

boolean isUserMuted(String username);

long getUserMuteTimeout(String username);

void setUserMuteTimeout(String username, long timestamp);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.github.aleksandarharalanov.chatguard.core.security.penalty;

import me.zavdav.zcore.api.Punishments;
import me.zavdav.zcore.data.Mute;
import me.zavdav.zcore.util.PlayerUtils;

import java.util.UUID;

public class ZCoreMuteHandler implements MuteHandler {

@Override
public boolean isUserMuted(String username) {
return Punishments.isPlayerMuted(PlayerUtils.getUUIDFromUsername(username));
}

@Override
public long getUserMuteTimeout(String username) {
UUID uuid = PlayerUtils.getUUIDFromUsername(username);
if (!Punishments.isPlayerMuted(uuid)) {
return System.currentTimeMillis();
}

Mute mute = Punishments.getMute(uuid);

// It is possible that getDuration() returns null, which specifies a permanent mute.
// In this case, return 100 years as the timeout.
if (mute.getDuration() == null) {
return 31_536_000L * 1000 * 100;
} else {
return mute.getDuration() * 1000;
}
}

@Override
public void setUserMuteTimeout(String username, long timestamp) {
Punishments.mutePlayer(PlayerUtils.getUUIDFromUsername(username),
null,
(timestamp - System.currentTimeMillis()) / 1000,
"Bad words in chat message");
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package io.github.aleksandarharalanov.chatguard.listener.player;

import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;
import io.github.aleksandarharalanov.chatguard.ChatGuard;
import io.github.aleksandarharalanov.chatguard.core.misc.TimeFormatter;
import io.github.aleksandarharalanov.chatguard.core.security.captcha.CaptchaDetector;
import io.github.aleksandarharalanov.chatguard.core.security.captcha.CaptchaHandler;
import io.github.aleksandarharalanov.chatguard.core.security.filter.ContentFilter;
import io.github.aleksandarharalanov.chatguard.core.security.penalty.MuteEnforcer;
import io.github.aleksandarharalanov.chatguard.core.security.spam.ChatRateLimiter;
import io.github.aleksandarharalanov.chatguard.util.auth.AccessUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerListener;
Expand All @@ -20,23 +18,21 @@ public class PlayerChatListener extends PlayerListener {
public void onPlayerChat(PlayerChatEvent event) {
Player player = event.getPlayer();

if (isPlayerEssentialsMuted(player, event)) return;
if (isPlayerMuted(player, event)) return;
if (hasBypassPermission(player)) return;
if (handleActiveCaptchaVerification(player, event)) return;
if (handleSpamPrevention(player, event)) return;
if (handleChatFiltering(player, event)) return;
if (handleCaptchaTriggerCheck(player, event)) return;
}

private static boolean isPlayerEssentialsMuted(Player player, PlayerChatEvent event) {
Essentials essentials = (Essentials) Bukkit.getServer().getPluginManager().getPlugin("Essentials");
if (essentials != null && essentials.isEnabled()) {
User user = essentials.getUser(player.getName());
if (user.isMuted()) {
TimeFormatter.printFormattedMuteDuration(user);
event.setCancelled(true);
return true;
}
private static boolean isPlayerMuted(Player player, PlayerChatEvent event) {
if (MuteEnforcer.muteHandler == null) return false;

if (MuteEnforcer.muteHandler.isUserMuted(player.getName())) {
TimeFormatter.printFormattedMuteDuration(player.getName());
event.setCancelled(true);
return true;
}
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ filter:
log:
console: true
local-file: true
essentials-mute:
auto-mute:
enabled: true
duration:
s0: "30m"
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ name: ChatGuard
author: Beezle
website: github.com/AleksandarHaralanov/ChatGuard
description: Prevents messages, usernames, and signs containing blocked terms or matching RegEx patterns, enforces mutes, stops chat and command spam, prompts captcha verification, logs actions, and applies escalating penalties.
softdepend: [Essentials]
softdepend: [Essentials, ZCore]

commands:
chatguard:
Expand Down