Исправлен фильтр чата: добавлена нормализация сообщений, защита от обхода фильтра, точный поиск слов с word boundaries

This commit is contained in:
loki5512344 2025-12-30 20:48:29 +01:00
parent d49261988e
commit 2292137986
3 changed files with 126 additions and 10 deletions

View file

@ -1,6 +1,7 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import com.loki.lochat.gradient.util.FoliaUtil;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
@ -61,9 +62,16 @@ public class ChatColorManager {
}
}
/**
* Асинхронное сохранение данных (для Folia совместимости)
*/
private void saveDataAsync() {
FoliaUtil.runAsync(plugin, this::saveData);
}
public void setChatColor(UUID playerId, String color) {
chatColors.put(playerId, color);
saveData();
saveDataAsync();
}
public String getChatColor(UUID playerId) {
@ -77,7 +85,7 @@ public class ChatColorManager {
public void removeChatColor(UUID playerId) {
chatColors.remove(playerId);
dataConfig.set(playerId.toString(), null);
saveData();
saveDataAsync();
}
/**

View file

@ -20,18 +20,49 @@ public class FilterManager {
WARNED
}
/**
* Проверяет сообщение на наличие запрещенных слов
*/
public FilterResult checkMessage(String message) {
if (!plugin.getConfigManager().isFilterEnabled()) {
return FilterResult.ALLOWED;
}
if (message == null || message.trim().isEmpty()) {
return FilterResult.ALLOWED;
}
List<String> badWords = plugin.getConfigManager().getFilterWords();
String lowerMessage = message.toLowerCase();
if (badWords == null || badWords.isEmpty()) {
return FilterResult.ALLOWED;
}
// Нормализуем сообщение (убираем обход фильтра)
String normalizedMessage = normalizeMessage(message);
String lowerMessage = normalizedMessage.toLowerCase();
for (String word : badWords) {
if (lowerMessage.contains(word.toLowerCase())) {
if (word == null || word.trim().isEmpty()) {
continue;
}
String lowerWord = word.toLowerCase().trim();
// Проверяем точное совпадение слова (с границами слов)
Pattern wordPattern = Pattern.compile("\\b" + Pattern.quote(lowerWord) + "\\b", Pattern.CASE_INSENSITIVE);
if (wordPattern.matcher(normalizedMessage).find()) {
String action = plugin.getConfigManager().getFilterAction();
return switch (action) {
return switch (action.toLowerCase()) {
case "block" -> FilterResult.BLOCKED;
case "warn" -> FilterResult.WARNED;
default -> FilterResult.CENSORED;
};
}
// Также проверяем как подстроку (для частичных совпадений типа "пизд")
if (lowerMessage.contains(lowerWord)) {
String action = plugin.getConfigManager().getFilterAction();
return switch (action.toLowerCase()) {
case "block" -> FilterResult.BLOCKED;
case "warn" -> FilterResult.WARNED;
default -> FilterResult.CENSORED;
@ -42,20 +73,89 @@ public class FilterManager {
return FilterResult.ALLOWED;
}
/**
* Цензурирует сообщение, заменяя запрещенные слова
*/
public String censorMessage(String message) {
if (!plugin.getConfigManager().isFilterEnabled()) {
return message;
}
if (message == null || message.trim().isEmpty()) {
return message;
}
List<String> badWords = plugin.getConfigManager().getFilterWords();
if (badWords == null || badWords.isEmpty()) {
return message;
}
String replacement = plugin.getConfigManager().getFilterReplacement();
if (replacement == null) {
replacement = "***";
}
String result = message;
String normalizedMessage = normalizeMessage(message);
for (String word : badWords) {
Pattern pattern = Pattern.compile("(?i)" + Pattern.quote(word));
result = pattern.matcher(result).replaceAll(replacement);
if (word == null || word.trim().isEmpty()) {
continue;
}
String lowerWord = word.toLowerCase().trim();
// Заменяем точные совпадения слов
Pattern wordPattern = Pattern.compile("\\b" + Pattern.quote(word) + "\\b", Pattern.CASE_INSENSITIVE);
result = wordPattern.matcher(result).replaceAll(replacement);
// Также заменяем как подстроку (для частичных совпадений)
Pattern substringPattern = Pattern.compile("(?i)" + Pattern.quote(word));
result = substringPattern.matcher(result).replaceAll(replacement);
}
return result;
}
/**
* Нормализует сообщение, убирая попытки обхода фильтра
* Заменяет специальные символы на обычные буквы
*/
private String normalizeMessage(String message) {
if (message == null) {
return "";
}
// Заменяем символы обхода на буквы (для обнаружения х*й, х_уй и т.д.)
String normalized = message;
// Заменяем символы обхода на буквы
normalized = normalized.replace('*', 'а');
normalized = normalized.replace('_', 'а');
normalized = normalized.replace('-', 'а');
normalized = normalized.replace('.', 'а');
normalized = normalized.replace(',', 'а');
normalized = normalized.replace('|', 'и');
normalized = normalized.replace('1', 'и');
normalized = normalized.replace('!', 'и');
normalized = normalized.replace('0', 'о');
normalized = normalized.replace('3', 'з');
normalized = normalized.replace('4', 'ч');
normalized = normalized.replace('5', 'с');
normalized = normalized.replace('6', 'б');
normalized = normalized.replace('7', 'т');
normalized = normalized.replace('8', 'в');
normalized = normalized.replace('9', 'д');
normalized = normalized.replace('@', 'а');
normalized = normalized.replace('#', 'х');
normalized = normalized.replace('$', 'с');
normalized = normalized.replace('%', 'о');
normalized = normalized.replace('^', 'х');
normalized = normalized.replace('&', 'а');
// Убираем множественные пробелы
normalized = normalized.replaceAll("\\s+", " ");
return normalized;
}
}

View file

@ -1,6 +1,7 @@
package com.loki.lochat.managers;
import com.loki.lochat.LoChat;
import com.loki.lochat.gradient.util.FoliaUtil;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
@ -69,7 +70,7 @@ public class IgnoreManager {
public boolean addIgnore(UUID player, UUID target) {
Set<UUID> ignored = ignoreMap.computeIfAbsent(player, k -> ConcurrentHashMap.newKeySet());
boolean added = ignored.add(target);
if (added) save();
if (added) saveAsync();
return added;
}
@ -77,7 +78,7 @@ public class IgnoreManager {
Set<UUID> ignored = ignoreMap.get(player);
if (ignored == null) return false;
boolean removed = ignored.remove(target);
if (removed) save();
if (removed) saveAsync();
return removed;
}
@ -92,6 +93,13 @@ public class IgnoreManager {
public void clearIgnores(UUID player) {
ignoreMap.remove(player);
save();
saveAsync();
}
/**
* Асинхронное сохранение данных (для Folia совместимости)
*/
private void saveAsync() {
FoliaUtil.runAsync(plugin, this::save);
}
}